diff --git a/Gruntfile.js b/Gruntfile.js index cc634ab..576df8e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -60,7 +60,7 @@ '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', - '<%= dirs.src %>/filters/GreyFilter.js', + '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', '<%= dirs.src %>/filters/PixelateFilter.js', '<%= dirs.src %>/filters/BlurXFilter.js', diff --git a/Gruntfile.js b/Gruntfile.js index cc634ab..576df8e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -60,7 +60,7 @@ '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', - '<%= dirs.src %>/filters/GreyFilter.js', + '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', '<%= dirs.src %>/filters/PixelateFilter.js', '<%= dirs.src %>/filters/BlurXFilter.js', diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index 21b0257..1e11684 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1,12289 +1,12548 @@ /** + * @license + * Pixi.JS - v1.3.0 + * Copyright (c) 2012, Mat Groves + * http://goodboydigital.com/ + * + * Compiled: 2013-11-20 + * + * Pixi.JS is licensed under the MIT License. + * http://www.opensource.org/licenses/mit-license.php + */ +/** * @author Mat Groves http://matgroves.com/ @Doormat23 */ (function(){ var root = this; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * @module PIXI - */ -var PIXI = PIXI || {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point - * @param y {Number} position of the point - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -} - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -} - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -} - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - - -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -} - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -} - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; - -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayobjects - * - * @class Circle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -} - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -} - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - - -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayobjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall width of this ellipse - * @param height {Number} The overall height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - //and a radius of 0.5 - var normx = ((x - this.x) / this.width) - 0.5, - normy = ((y - this.y) / this.height) - 0.5; - - normx *= normx; - normy *= normy; - - return (normx + normy < 0.25); -} - -PIXI.Ellipse.getBounds = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - - - -/* - * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV - * you both rock! - */ - -function determineMatrixArrayType() { - PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; - return PIXI.Matrix; -} - -determineMatrixArrayType(); - -PIXI.mat3 = {}; - -PIXI.mat3.create = function() -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat3.identity = function(matrix) -{ - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat4 = {}; - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat3.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], - a10 = mat[3], a11 = mat[4], a12 = mat[5], - a20 = mat[6], a21 = mat[7], a22 = mat[8], - - b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], - b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], - b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - - dest[0] = b00 * a00 + b01 * a10 + b02 * a20; - dest[1] = b00 * a01 + b01 * a11 + b02 * a21; - dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - - dest[3] = b10 * a00 + b11 * a10 + b12 * a20; - dest[4] = b10 * a01 + b11 * a11 + b12 * a21; - dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - - dest[6] = b20 * a00 + b21 * a10 + b22 * a20; - dest[7] = b20 * a01 + b21 * a11 + b22 * a21; - dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - - return dest; -} - -PIXI.mat3.clone = function(mat) -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = mat[0]; - matrix[1] = mat[1]; - matrix[2] = mat[2]; - matrix[3] = mat[3]; - matrix[4] = mat[4]; - matrix[5] = mat[5]; - matrix[6] = mat[6]; - matrix[7] = mat[7]; - matrix[8] = mat[8]; - - return matrix; -} - -PIXI.mat3.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) { - var a01 = mat[1], a02 = mat[2], - a12 = mat[5]; - - mat[1] = mat[3]; - mat[2] = mat[6]; - mat[3] = a01; - mat[5] = mat[7]; - mat[6] = a02; - mat[7] = a12; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[3]; - dest[2] = mat[6]; - dest[3] = mat[1]; - dest[4] = mat[4]; - dest[5] = mat[7]; - dest[6] = mat[2]; - dest[7] = mat[5]; - dest[8] = mat[8]; - return dest; -} - -PIXI.mat3.toMat4 = function (mat, dest) -{ - if (!dest) { dest = PIXI.mat4.create(); } - - dest[15] = 1; - dest[14] = 0; - dest[13] = 0; - dest[12] = 0; - - dest[11] = 0; - dest[10] = mat[8]; - dest[9] = mat[7]; - dest[8] = mat[6]; - - dest[7] = 0; - dest[6] = mat[5]; - dest[5] = mat[4]; - dest[4] = mat[3]; - - dest[3] = 0; - dest[2] = mat[2]; - dest[1] = mat[1]; - dest[0] = mat[0]; - - return dest; -} - - -///// - - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat4.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) - { - var a01 = mat[1], a02 = mat[2], a03 = mat[3], - a12 = mat[6], a13 = mat[7], - a23 = mat[11]; - - mat[1] = mat[4]; - mat[2] = mat[8]; - mat[3] = mat[12]; - mat[4] = a01; - mat[6] = mat[9]; - mat[7] = mat[13]; - mat[8] = a02; - mat[9] = a12; - mat[11] = mat[14]; - mat[12] = a03; - mat[13] = a13; - mat[14] = a23; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[4]; - dest[2] = mat[8]; - dest[3] = mat[12]; - dest[4] = mat[1]; - dest[5] = mat[5]; - dest[6] = mat[9]; - dest[7] = mat[13]; - dest[8] = mat[2]; - dest[9] = mat[6]; - dest[10] = mat[10]; - dest[11] = mat[14]; - dest[12] = mat[3]; - dest[13] = mat[7]; - dest[14] = mat[11]; - dest[15] = mat[15]; - return dest; -} - -PIXI.mat4.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; - var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; - var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; - var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - - // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; - dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[4]; - b1 = mat2[5]; - b2 = mat2[6]; - b3 = mat2[7]; - dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[8]; - b1 = mat2[9]; - b2 = mat2[10]; - b3 = mat2[11]; - dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[12]; - b1 = mat2[13]; - b2 = mat2[14]; - b3 = mat2[15]; - dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - return dest; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The base class for all objects that are rendered on the screen. - * - * @class DisplayObject - * @constructor - */ -PIXI.DisplayObject = function() -{ - this.last = this; - this.first = this; - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @property position - * @type Point - */ - this.position = new PIXI.Point(); - - /** - * The scale factor of the object. - * - * @property scale - * @type Point - */ - this.scale = new PIXI.Point(1,1);//{x:1, y:1}; - - /** - * The pivot point of the displayObject that it rotates around - * - * @property pivot - * @type Point - */ - this.pivot = new PIXI.Point(0,0); - - /** - * The rotation of the object in radians. - * - * @property rotation - * @type Number - */ - this.rotation = 0; - - /** - * The opacity of the object. - * - * @property alpha - * @type Number - */ - this.alpha = 1; - - /** - * The visibility of the object. - * - * @property visible - * @type Boolean - */ - this.visible = true; - - /** - * This is the defined area that will pick up mouse / touch events. It is null by default. - * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) - * - * @property hitArea - * @type Rectangle|Circle|Ellipse|Polygon - */ - this.hitArea = null; - - /** - * This is used to indicate if the displayObject should display a mouse hand cursor on rollover - * - * @property buttonMode - * @type Boolean - */ - this.buttonMode = false; - - /** - * Can this object be rendered - * - * @property renderable - * @type Boolean - */ - this.renderable = false; - - /** - * [read-only] The display object container that contains this display object. - * - * @property parent - * @type DisplayObjectContainer - * @readOnly - */ - this.parent = null; - - /** - * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. - * - * @property stage - * @type Stage - * @readOnly - */ - this.stage = null; - - /** - * [read-only] The multiplied alpha of the displayobject - * - * @property worldAlpha - * @type Number - * @readOnly - */ - this.worldAlpha = 1; - - /** - * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property - * - * @property _interactive - * @type Boolean - * @readOnly - * @private - */ - this._interactive = false; - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [read-only] Current transform of the object locally - * - * @property localTransform - * @type Mat3 - * @readOnly - * @private - */ - this.localTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [NYI] Unkown - * - * @property color - * @type Array<> - * @private - */ - this.color = []; - - /** - * [NYI] Holds whether or not this object is dynamic, for rendering optimization - * - * @property dynamic - * @type Boolean - * @private - */ - this.dynamic = true; - - // chach that puppy! - this._sr = 0; - this._cr = 1; - - - this.filterArea = new PIXI.Rectangle(0,0,1,1); - - /* - * MOUSE Callbacks - */ - - /** - * A callback that is used when the users clicks on the displayObject with their mouse - * @method click - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user clicks the mouse down over the sprite - * @method mousedown - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject - * for this callback to be fired the mouse must have been pressed down over the displayObject - * @method mouseup - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject - * for this callback to be fired, The touch must have started over the displayObject - * @method mouseupoutside - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse rolls over the displayObject - * @method mouseover - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse leaves the displayObject - * @method mouseout - * @param interactionData {InteractionData} - */ - - - /* - * TOUCH Callbacks - */ - - /** - * A callback that is used when the users taps on the sprite with their finger - * basically a touch version of click - * @method tap - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user touch's over the displayObject - * @method touchstart - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases a touch over the displayObject - * @method touchend - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the touch that was over the displayObject - * for this callback to be fired, The touch must have started over the sprite - * @method touchendoutside - * @param interactionData {InteractionData} - */ -} - -// constructor -PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; - -/** - * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default - * Instead of using this function you can now simply set the interactive property to true or false - * - * @method setInteractive - * @param interactive {Boolean} - * @deprecated Simply set the `interactive` property directly - */ -PIXI.DisplayObject.prototype.setInteractive = function(interactive) -{ - this.interactive = interactive; -} - -/** - * Indicates if the sprite will have touch and mouse interactivity. It is false by default - * - * @property interactive - * @type Boolean - * @default false - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { - get: function() { - return this._interactive; - }, - set: function(value) { - this._interactive = value; - - // TODO more to be done here.. - // need to sort out a re-crawl! - if(this.stage)this.stage.dirty = true; - } -}); - -/** - * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. - * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. - * To remove a mask, set this property to null. - * - * @property mask - * @type Graphics - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { - get: function() { - return this._mask; - }, - set: function(value) { - - - if(value) - { - if(this._mask) - { - value.start = this._mask.start; - value.end = this._mask.end; - } - else - { - this.addFilter(value); - value.renderable = false; - } - } - else - { - this.removeFilter(this._mask); - this._mask.renderable = true; - } - - this._mask = value; - } -}); - -/** - * Sets the filters for the displayObject. - * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. - * To remove filters simply set this property to 'null' - * @property filters - * @type Array An array of filters - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { - get: function() { - return this._filters; - }, - set: function(value) { - - if(value) - { - if(this._filters)this.removeFilter(this._filters); - this.addFilter(value); - - // now put all the passes in one place.. - var passes = []; - for (var i = 0; i < value.length; i++) - { - var filterPasses = value[i].passes; - for (var j = 0; j < filterPasses.length; j++) - { - passes.push(filterPasses[j]); - }; - }; - - value.start.filterPasses = passes; - } - else - { - if(this._filters)this.removeFilter(this._filters); - } - - this._filters = value; - - - - - } -}); - -/* - * Adds a filter to this displayObject - * - * @method addFilter - * @param mask {Graphics} the graphics object to use as a filter - * @private - */ -PIXI.DisplayObject.prototype.addFilter = function(data) -{ - //if(this.filter)return; - //this.filter = true; -// data[0].target = this; - - - // insert a filter block.. - // TODO Onject pool thease bad boys.. - var start = new PIXI.FilterBlock(); - var end = new PIXI.FilterBlock(); - - data.start = start; - data.end = end; - - start.data = data; - end.data = data; - - start.first = start.last = this; - end.first = end.last = this; - - start.open = true; - - start.target = this; - - /* - * insert start - */ - - var childFirst = start - var childLast = start - var nextObject; - var previousObject; - - previousObject = this.first._iPrev; - - if(previousObject) - { - nextObject = previousObject._iNext; - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - } - else - { - nextObject = this; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - - // now insert the end filter block.. - - /* - * insert end filter - */ - var childFirst = end - var childLast = end - var nextObject = null; - var previousObject = null; - - previousObject = this.last; - nextObject = previousObject._iNext; - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - var updateLast = this; - - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = end; - } - updateLast = updateLast.parent; - } - - this.first = start; - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.addFilterBlocks(start, end); - } - -} - -/* - * Removes the filter to this displayObject - * - * @method removeFilter - * @private - */ -PIXI.DisplayObject.prototype.removeFilter = function(data) -{ - //if(!this.filter)return; - //this.filter = false; - console.log("YUOIO") - // modify the list.. - var startBlock = data.start; - - - var nextObject = startBlock._iNext; - var previousObject = startBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - if(previousObject)previousObject._iNext = nextObject; - - this.first = startBlock._iNext; - - // remove the end filter - var lastBlock = data.end; - - var nextObject = lastBlock._iNext; - var previousObject = lastBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - // this is always true too! - var tempLast = lastBlock._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == lastBlock) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); - } -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObject.prototype.updateTransform = function() -{ - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); - } - - var localTransform = this.localTransform; - var parentTransform = this.parent.worldTransform; - var worldTransform = this.worldTransform; - //console.log(localTransform) - localTransform[0] = this._cr * this.scale.x; - localTransform[1] = -this._sr * this.scale.y - localTransform[3] = this._sr * this.scale.x; - localTransform[4] = this._cr * this.scale.y; - - // TODO --> do we even need a local matrix??? - - var px = this.pivot.x; - var py = this.pivot.y; - - // Cache the matrix values (makes for huge speed increases!) - var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], - a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], - - b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], - b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; - - localTransform[2] = a02 - localTransform[5] = a12 - - worldTransform[0] = b00 * a00 + b01 * a10; - worldTransform[1] = b00 * a01 + b01 * a11; - worldTransform[2] = b00 * a02 + b01 * a12 + b02; - - worldTransform[3] = b10 * a00 + b11 * a10; - worldTransform[4] = b10 * a01 + b11 * a11; - worldTransform[5] = b10 * a02 + b11 * a12 + b12; - - // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! - // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); - this.worldAlpha = this.alpha * this.parent.worldAlpha; - - this.vcount = PIXI.visibleCount; - -} - -PIXI.visibleCount = 0; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A DisplayObjectContainer represents a collection of display objects. - * It is the base class of all display objects that act as a container for other objects. - * - * @class DisplayObjectContainer - * @extends DisplayObject - * @constructor - */ -PIXI.DisplayObjectContainer = function() -{ - PIXI.DisplayObject.call( this ); - - /** - * [read-only] The of children of this container. - * - * @property children - * @type Array - * @readOnly - */ - this.children = []; -} - -// constructor -PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; - -/** - * Adds a child to the container. - * - * @method addChild - * @param child {DisplayObject} The DisplayObject to add to the container - */ -PIXI.DisplayObjectContainer.prototype.addChild = function(child) -{ - if(child.parent != undefined) - { - - //// COULD BE THIS??? - child.parent.removeChild(child); - // return; - } - - child.parent = this; - - this.children.push(child); - - // update the stage refference.. - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // LINKED LIST // - - // modify the list.. - var childFirst = child.first - var childLast = child.last; - var nextObject; - var previousObject; - - // this could be wrong if there is a filter?? - if(this._filters || this._mask) - { - previousObject = this.last._iPrev; - } - else - { - previousObject = this.last; - } - - nextObject = previousObject._iNext; - - // always true in this case - // need to make sure the parents last is updated too - var updateLast = this; - var prevLast = previousObject; - - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - -} - -/** - * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown - * - * @method addChildAt - * @param child {DisplayObject} The child to add - * @param index {Number} The index to place the child in - */ -PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) -{ - if(index >= 0 && index <= this.children.length) - { - if(child.parent != undefined) - { - child.parent.removeChild(child); - } - child.parent = this; - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - var nextObject; - var previousObject; - - if(index == this.children.length) - { - previousObject = this.last; - var updateLast = this; - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - } - else if(index == 0) - { - previousObject = this; - } - else - { - previousObject = this.children[index-1].last; - } - - nextObject = previousObject._iNext; - - // always true in this case - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - this.children.splice(index, 0, child); - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - - } - else - { - throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); - } -} - -/** - * [NYI] Swaps the depth of 2 displayObjects - * - * @method swapChildren - * @param child {DisplayObject} - * @param child2 {DisplayObject} - * @private - */ -PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) -{ - /* - * this funtion needs to be recoded.. - * can be done a lot faster.. - */ - return; - - // need to fix this function :/ - /* - // TODO I already know this?? - var index = this.children.indexOf( child ); - var index2 = this.children.indexOf( child2 ); - - if ( index !== -1 && index2 !== -1 ) - { - // cool - - /* - if(this.stage) - { - // this is to satisfy the webGL batching.. - // TODO sure there is a nicer way to achieve this! - this.stage.__removeChild(child); - this.stage.__removeChild(child2); - - this.stage.__addChild(child); - this.stage.__addChild(child2); - } - - // swap the positions.. - this.children[index] = child2; - this.children[index2] = child; - - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - }*/ -} - -/** - * Returns the Child at the specified index - * - * @method getChildAt - * @param index {Number} The index to get the child from - */ -PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) -{ - if(index >= 0 && index < this.children.length) - { - return this.children[index]; - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - } -} - -/** - * Removes a child from the container. - * - * @method removeChild - * @param child {DisplayObject} The DisplayObject to remove - */ -PIXI.DisplayObjectContainer.prototype.removeChild = function(child) -{ - var index = this.children.indexOf( child ); - if ( index !== -1 ) - { - // unlink // - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - - var nextObject = childLast._iNext; - var previousObject = childFirst._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - if(this.last == childLast) - { - var tempLast = childFirst._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == childLast.last) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - } - - childLast._iNext = null; - childFirst._iPrev = null; - - // update the stage reference.. - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = null; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // webGL trim - if(child.__renderGroup) - { - child.__renderGroup.removeDisplayObjectAndChildren(child); - } - - child.parent = undefined; - this.children.splice( index, 1 ); - } - else - { - throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); - } -} - -/* - * Updates the container's children's transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObjectContainer.prototype.updateTransform = function() -{ - if(!this.visible)return; - - PIXI.DisplayObject.prototype.updateTransform.call( this ); - - for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation - */ -PIXI.MovieClip = function(textures) -{ - PIXI.Sprite.call(this, textures[0]); - - /** - * The array of textures that make up the animation - * - * @property textures - * @type Array - */ - this.textures = textures; - - /** - * The speed that the MovieClip will play at. Higher is faster, lower is slower - * - * @property animationSpeed - * @type Number - * @default 1 - */ - this.animationSpeed = 1; - - /** - * Whether or not the movie clip repeats after playing. - * - * @property loop - * @type Boolean - * @default true - */ - this.loop = true; - - /** - * Function to call when a MovieClip finishes playing - * - * @property onComplete - * @type Function - */ - this.onComplete = null; - - /** - * [read-only] The index MovieClips current frame (this may not have to be a whole number) - * - * @property currentFrame - * @type Number - * @default 0 - * @readOnly - */ - this.currentFrame = 0; - - /** - * [read-only] Indicates if the MovieClip is currently playing - * - * @property playing - * @type Boolean - * @readOnly - */ - this.playing = false; -} - -// constructor -PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); -PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; - -/** -* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures -* assigned to the MovieClip. -* -* @property totalFrames -* @type Number -* @default 0 -* @readOnly -*/ -Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { - get: function() { - - return this.textures.length; - } -}); - - -/** - * Stops the MovieClip - * - * @method stop - */ -PIXI.MovieClip.prototype.stop = function() -{ - this.playing = false; -} - -/** - * Plays the MovieClip - * - * @method play - */ -PIXI.MovieClip.prototype.play = function() -{ - this.playing = true; -} - -/** - * Stops the MovieClip and goes to a specific frame - * - * @method gotoAndStop - * @param frameNumber {Number} frame index to stop at - */ -PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) -{ - this.playing = false; - this.currentFrame = frameNumber; - var round = (this.currentFrame + 0.5) | 0; - this.setTexture(this.textures[round % this.textures.length]); -} - -/** - * Goes to a specific frame and begins playing the MovieClip - * - * @method gotoAndPlay - * @param frameNumber {Number} frame index to start at - */ -PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) -{ - this.currentFrame = frameNumber; - this.playing = true; -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.MovieClip.prototype.updateTransform = function() -{ - PIXI.Sprite.prototype.updateTransform.call(this); - - if(!this.playing)return; - - this.currentFrame += this.animationSpeed; - - var round = (this.currentFrame + 0.5) | 0; - - if(this.loop || round < this.textures.length) - { - this.setTexture(this.textures[round % this.textures.length]); - } - else if(round >= this.textures.length) - { - this.gotoAndStop(this.textures.length - 1); - if(this.onComplete) - { - this.onComplete(); - } - } -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - - -PIXI.FilterBlock = function() -{ - this.visible = true; - this.renderable = true; -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text to split a line you can use "\n" - * - * @class Text - * @extends Sprite - * @constructor - * @param text {String} The copy that you would like the text to display - * @param [style] {Object} The style parameters - * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text = function(text, style) -{ - this.canvas = document.createElement("canvas"); - this.context = this.canvas.getContext("2d"); - PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); - - this.setText(text); - this.setStyle(style); - - this.updateText(); - this.dirty = false; -}; - -// constructor -PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); -PIXI.Text.prototype.constructor = PIXI.Text; - -/** - * Set the style of the text - * - * @method setStyle - * @param [style] {Object} The style parameters - * @param [style.font="bold 20pt Arial"] {String} The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text.prototype.setStyle = function(style) -{ - style = style || {}; - style.font = style.font || "bold 20pt Arial"; - style.fill = style.fill || "black"; - style.align = style.align || "left"; - style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 - style.strokeThickness = style.strokeThickness || 0; - style.wordWrap = style.wordWrap || false; - style.wordWrapWidth = style.wordWrapWidth || 100; - this.style = style; - this.dirty = true; -}; - -/** - * Set the copy for the text object. To split a line you can use "\n" - * - * @methos setText - * @param {String} text The copy that you would like the text to display - */ -PIXI.Text.prototype.setText = function(text) -{ - this.text = text.toString() || " "; - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.Text.prototype.updateText = function() -{ - this.context.font = this.style.font; - - var outputText = this.text; - - // word wrap - // preserve original text - if(this.style.wordWrap)outputText = this.wordWrap(this.text); - - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - //calculate text width - var lineWidths = []; - var maxLineWidth = 0; - for (var i = 0; i < lines.length; i++) - { - var lineWidth = this.context.measureText(lines[i]).width; - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - this.canvas.width = maxLineWidth + this.style.strokeThickness; - - //calculate text height - var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; - this.canvas.height = lineHeight * lines.length; - - //set canvas text styles - this.context.fillStyle = this.style.fill; - this.context.font = this.style.font; - - this.context.strokeStyle = this.style.stroke; - this.context.lineWidth = this.style.strokeThickness; - - this.context.textBaseline = "top"; - - //draw lines line by line - for (i = 0; i < lines.length; i++) - { - var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - - if(this.style.align == "right") - { - linePosition.x += maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - linePosition.x += (maxLineWidth - lineWidths[i]) / 2; - } - - if(this.style.stroke && this.style.strokeThickness) - { - this.context.strokeText(lines[i], linePosition.x, linePosition.y); - } - - if(this.style.fill) - { - this.context.fillText(lines[i], linePosition.x, linePosition.y); - } - } - - this.updateTexture(); -}; - -/** - * Updates texture size based on canvas size - * - * @method updateTexture - * @private - */ -PIXI.Text.prototype.updateTexture = function() -{ - this.texture.baseTexture.width = this.canvas.width; - this.texture.baseTexture.height = this.canvas.height; - this.texture.frame.width = this.canvas.width; - this.texture.frame.height = this.canvas.height; - - this._width = this.canvas.width; - this._height = this.canvas.height; - - PIXI.texturesToUpdate.push(this.texture.baseTexture); -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.Text.prototype.updateTransform = function() -{ - if(this.dirty) - { - this.updateText(); - this.dirty = false; - } - - PIXI.Sprite.prototype.updateTransform.call(this); -}; - -/* - * http://stackoverflow.com/users/34441/ellisbben - * great solution to the problem! - * - * @method determineFontHeight - * @param fontStyle {Object} - * @private - */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) -{ - // build a little reference dictionary so if the font style has been used return a - // cached version... - var result = PIXI.Text.heightCache[fontStyle]; - - if(!result) - { - var body = document.getElementsByTagName("body")[0]; - var dummy = document.createElement("div"); - var dummyText = document.createTextNode("M"); - dummy.appendChild(dummyText); - dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); - body.appendChild(dummy); - - result = dummy.offsetHeight; - PIXI.Text.heightCache[fontStyle] = result; - - body.removeChild(dummy); - } - - return result; -}; - -/** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. - * - * @method wordWrap - * @param text {String} - * @private - */ -PIXI.Text.prototype.wordWrap = function(text) -{ - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ""; - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) - { - var spaceLeft = this.style.wordWrapWidth; - var words = lines[i].split(" "); - for (var j = 0; j < words.length; j++) - { - var wordWidth = this.context.measureText(words[j]).width; - var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; - if(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 = this.style.wordWrapWidth - wordWidth; - } - else - { - spaceLeft -= wordWidthWithSpace; - result += words[j] + " "; - } - } - result += "\n"; - } - return result; -}; - -/** - * Destroys this text object - * - * @method destroy - * @param destroyTexture {Boolean} - */ -PIXI.Text.prototype.destroy = function(destroyTexture) -{ - if(destroyTexture) - { - this.texture.destroy(); - } - -}; - -PIXI.Text.heightCache = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using - * http://www.angelcode.com/products/bmfont/ for windows or - * http://www.bmglyph.com/ for mac. - * - * @class BitmapText - * @extends DisplayObjectContainer - * @constructor - * @param text {String} The copy that you would like the text to display - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText = function(text, style) -{ - PIXI.DisplayObjectContainer.call(this); - - this.setText(text); - this.setStyle(style); - this.updateText(); - this.dirty = false - -}; - -// constructor -PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; - -/** - * Set the copy for the text object - * - * @method setText - * @param text {String} The copy that you would like the text to display - */ -PIXI.BitmapText.prototype.setText = function(text) -{ - this.text = text || " "; - this.dirty = true; -}; - -/** - * Set the style of the text - * - * @method setStyle - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText.prototype.setStyle = function(style) -{ - style = style || {}; - style.align = style.align || "left"; - this.style = style; - - var font = style.font.split(" "); - this.fontName = font[font.length - 1]; - this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; - - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.BitmapText.prototype.updateText = function() -{ - var data = PIXI.BitmapText.fonts[this.fontName]; - var pos = new PIXI.Point(); - var prevCharCode = null; - var chars = []; - var maxLineWidth = 0; - var lineWidths = []; - var line = 0; - var scale = this.fontSize / data.size; - for(var i = 0; i < this.text.length; i++) - { - var charCode = this.text.charCodeAt(i); - if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) - { - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - line++; - - pos.x = 0; - pos.y += data.lineHeight; - prevCharCode = null; - continue; - } - - var charData = data.chars[charCode]; - if(!charData) continue; - - if(prevCharCode && charData[prevCharCode]) - { - pos.x += charData.kerning[prevCharCode]; - } - chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); - pos.x += charData.xAdvance; - - prevCharCode = charCode; - } - - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - - var lineAlignOffsets = []; - for(i = 0; i <= line; i++) - { - var alignOffset = 0; - if(this.style.align == "right") - { - alignOffset = maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - alignOffset = (maxLineWidth - lineWidths[i]) / 2; - } - lineAlignOffsets.push(alignOffset); - } - - for(i = 0; i < chars.length; i++) - { - var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); - c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; - c.position.y = chars[i].position.y * scale; - c.scale.x = c.scale.y = scale; - this.addChild(c); - } - - this.width = pos.x * scale; - this.height = (pos.y + data.lineHeight) * scale; -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.BitmapText.prototype.updateTransform = function() -{ - if(this.dirty) - { - while(this.children.length > 0) - { - this.removeChild(this.getChildAt(0)); - } - this.updateText(); - - this.dirty = false; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - -PIXI.BitmapText.fonts = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - /** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive - * This manager also supports multitouch. - * - * @class InteractionManager - * @constructor - * @param stage {Stage} The stage to handle interactions - */ -PIXI.InteractionManager = function(stage) -{ - /** - * a refference to the stage - * - * @property stage - * @type Stage - */ - this.stage = stage; - - /** - * the mouse data - * - * @property mouse - * @type InteractionData - */ - this.mouse = new PIXI.InteractionData(); - - /** - * an object that stores current touches (InteractionData) by id reference - * - * @property touchs - * @type Object - */ - this.touchs = {}; - - - - // helpers - this.tempPoint = new PIXI.Point(); - //this.tempMatrix = mat3.create(); - - this.mouseoverEnabled = true; - - //tiny little interactiveData pool! - this.pool = []; - - this.interactiveItems = []; - this.interactionDOMElement = null; - - //this will make it so that you dont have to call bind all the time - this.onMouseMove = this.onMouseMove.bind( this ); - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseOut = this.onMouseOut.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - - this.onTouchStart = this.onTouchStart.bind(this); - this.onTouchEnd = this.onTouchEnd.bind(this); - this.onTouchMove = this.onTouchMove.bind(this); - - - this.last = 0; -} - -// constructor -PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; - -/** - * Collects an interactive sprite recursively to have their interactions managed - * - * @method collectInteractiveSprite - * @param displayObject {DisplayObject} the displayObject to collect - * @param iParent {DisplayObject} - * @private - */ -PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) -{ - var children = displayObject.children; - var length = children.length; - - /// make an interaction tree... {item.__interactiveParent} - for (var i = length-1; i >= 0; i--) - { - var child = children[i]; - -// if(child.visible) { - // push all interactive bits - if(child.interactive) - { - iParent.interactiveChildren = true; - //child.__iParent = iParent; - this.interactiveItems.push(child); - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, child); - } - } - else - { - child.__iParent = null; - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, iParent); - } - } -// } - } -} - -/** - * Sets the target for event delegation - * - * @method setTarget - * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to - * @private - */ -PIXI.InteractionManager.prototype.setTarget = function(target) -{ - this.target = target; - - //check if the dom element has been set. If it has don't do anything - if( this.interactionDOMElement === null ) { - - this.setTargetDomElement( target.view ); - } - - document.body.addEventListener('mouseup', this.onMouseUp, true); -} - - -/** - * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM - * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element - * to receive those events - * - * @method setTargetDomElement - * @param domElement {DOMElement} the dom element which will receive mouse and touch events - * @private - */ -PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) -{ - //remove previouse listeners - if( this.interactionDOMElement !== null ) - { - this.interactionDOMElement.style['-ms-content-zooming'] = ''; - this.interactionDOMElement.style['-ms-touch-action'] = ''; - - this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - } - - - if (window.navigator.msPointerEnabled) - { - // time to remove some of that zoom in ja.. - domElement.style['-ms-content-zooming'] = 'none'; - domElement.style['-ms-touch-action'] = 'none'; - - // DO some window specific touch! - } - - this.interactionDOMElement = domElement; - - domElement.addEventListener('mousemove', this.onMouseMove, true); - domElement.addEventListener('mousedown', this.onMouseDown, true); - domElement.addEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - domElement.addEventListener('touchstart', this.onTouchStart, true); - domElement.addEventListener('touchend', this.onTouchEnd, true); - domElement.addEventListener('touchmove', this.onTouchMove, true); -} - - -/** - * updates the state of interactive objects - * - * @method update - * @private - */ -PIXI.InteractionManager.prototype.update = function() -{ - if(!this.target)return; - - // frequency of 30fps?? - var now = Date.now(); - var diff = now - this.last; - diff = (diff * 30) / 1000; - if(diff < 1)return; - this.last = now; - // - - // ok.. so mouse events?? - // yes for now :) - // OPTIMSE - how often to check?? - if(this.dirty) - { - this.dirty = false; - - var len = this.interactiveItems.length; - - for (var i=0; i < len; i++) { - this.interactiveItems[i].interactiveChildren = false; - } - - this.interactiveItems = []; - - if(this.stage.interactive)this.interactiveItems.push(this.stage); - // go through and collect all the objects that are interactive.. - this.collectInteractiveSprite(this.stage, this.stage); - } - - // loop through interactive objects! - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - - //if(!item.visible)continue; - - // OPTIMISATION - only calculate every time if the mousemove function exists.. - // OK so.. does the object have any other interactive functions? - // hit-test the clip! - - - if(item.mouseover || item.mouseout || item.buttonMode) - { - // ok so there are some functions so lets hit test it.. - item.__hit = this.hitTest(item, this.mouse); - this.mouse.target = item; - // ok so deal with interactions.. - // loks like there was a hit! - if(item.__hit) - { - if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; - - if(!item.__isOver) - { - - if(item.mouseover)item.mouseover(this.mouse); - item.__isOver = true; - } - } - else - { - if(item.__isOver) - { - // roll out! - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } - } - - // ---> - } -} - -/** - * Is called when the mouse moves accross the renderer element - * - * @method onMouseMove - * @param event {Event} The DOM event of the mouse moving - * @private - */ -PIXI.InteractionManager.prototype.onMouseMove = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.interactionDOMElement.getBoundingClientRect(); - - this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); - this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); - - var length = this.interactiveItems.length; - var global = this.mouse.global; - - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousemove) - { - //call the function! - item.mousemove(this.mouse); - } - } -} - -/** - * Is called when the mouse button is pressed down on the renderer element - * - * @method onMouseDown - * @param event {Event} The DOM event of a mouse button being pressed down - * @private - */ -PIXI.InteractionManager.prototype.onMouseDown = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - // loop through inteaction tree... - // hit test each item! -> - // get interactive items under point?? - //stage.__i - var length = this.interactiveItems.length; - var global = this.mouse.global; - - var index = 0; - var parent = this.stage; - - // while - // hit test - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousedown || item.click) - { - item.__mouseIsDown = true; - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit) - { - //call the function! - if(item.mousedown)item.mousedown(this.mouse); - item.__isDown = true; - - // just the one! - if(!item.interactiveChildren)break; - } - } - } -} - - -PIXI.InteractionManager.prototype.onMouseOut = function(event) -{ - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.__isOver) - { - this.mouse.target = item; - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } -} - -/** - * Is called when the mouse button is released on the renderer element - * - * @method onMouseUp - * @param event {Event} The DOM event of a mouse button being released - * @private - */ -PIXI.InteractionManager.prototype.onMouseUp = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var global = this.mouse.global; - - - var length = this.interactiveItems.length; - var up = false; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mouseup || item.mouseupoutside || item.click) - { - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit && !up) - { - //call the function! - if(item.mouseup) - { - item.mouseup(this.mouse); - } - if(item.__isDown) - { - if(item.click)item.click(this.mouse); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.mouseupoutside)item.mouseupoutside(this.mouse); - } - } - - item.__isDown = false; - } - } -} - -/** - * Tests if the current mouse coords hit a sprite - * - * @method hitTest - * @param item {DisplayObject} The displayObject to test for a hit - * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit - * @private - */ -PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) -{ - var global = interactionData.global; - - if(item.vcount !== PIXI.visibleCount)return false; - - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, - a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10), - x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; - - interactionData.target = item; - - //a sprite or display object with a hit area defined - if(item.hitArea && item.hitArea.contains) { - if(item.hitArea.contains(x, y)) { - //if(isSprite) - interactionData.target = item; - - return true; - } - - return false; - } - // a sprite with no hitarea defined - else if(isSprite) - { - var width = item.texture.frame.width, - height = item.texture.frame.height, - x1 = -width * item.anchor.x, - y1; - - if(x > x1 && x < x1 + width) - { - y1 = -height * item.anchor.y; - - if(y > y1 && y < y1 + height) - { - // set the target property if a hit is true! - interactionData.target = item - return true; - } - } - } - - var length = item.children.length; - - for (var i = 0; i < length; i++) - { - var tempItem = item.children[i]; - var hit = this.hitTest(tempItem, interactionData); - if(hit) - { - // hmm.. TODO SET CORRECT TARGET? - interactionData.target = item - return true; - } - } - - return false; -} - -/** - * Is called when a touch is moved accross the renderer element - * - * @method onTouchMove - * @param event {Event} The DOM event of a touch moving accross the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchMove = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - touchData.originalEvent = event || window.event; - - // update the touch position - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - } - - var length = this.interactiveItems.length; - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - if(item.touchmove)item.touchmove(touchData); - } -} - -/** - * Is called when a touch is started on the renderer element - * - * @method onTouchStart - * @param event {Event} The DOM event of a touch starting on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchStart = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - - var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - - var touchData = this.pool.pop(); - if(!touchData)touchData = new PIXI.InteractionData(); - - touchData.originalEvent = event || window.event; - - this.touchs[touchEvent.identifier] = touchData; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - - if(item.touchstart || item.tap) - { - item.__hit = this.hitTest(item, touchData); - - if(item.__hit) - { - //call the function! - if(item.touchstart)item.touchstart(touchData); - item.__isDown = true; - item.__touchData = touchData; - - if(!item.interactiveChildren)break; - } - } - } - } -} - -/** - * Is called when a touch is ended on the renderer element - * - * @method onTouchEnd - * @param event {Event} The DOM event of a touch ending on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchEnd = function(event) -{ - //this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - var up = false; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - var itemTouchData = item.__touchData; // <-- Here! - item.__hit = this.hitTest(item, touchData); - - if(itemTouchData == touchData) - { - // so this one WAS down... - touchData.originalEvent = event || window.event; - // hitTest?? - - if(item.touchend || item.tap) - { - if(item.__hit && !up) - { - if(item.touchend)item.touchend(touchData); - if(item.__isDown) - { - if(item.tap)item.tap(touchData); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.touchendoutside)item.touchendoutside(touchData); - } - } - - item.__isDown = false; - } - - item.__touchData = null; - - } - else - { - - } - } - // remove the touch.. - this.pool.push(touchData); - this.touchs[touchEvent.identifier] = null; - } -} - -/** - * Holds all information related to an Interaction event - * - * @class InteractionData - * @constructor - */ -PIXI.InteractionData = function() -{ - /** - * This point stores the global coords of where the touch/mouse event happened - * - * @property global - * @type Point - */ - this.global = new PIXI.Point(); - - // this is here for legacy... but will remove - this.local = new PIXI.Point(); - - /** - * The target Sprite that was interacted with - * - * @property target - * @type Sprite - */ - this.target; - - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @property originalEvent - * @type Event - */ - this.originalEvent; -} - -/** - * This will return the local coords of the specified displayObject for this InteractionData - * - * @method getLocalPosition - * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off - * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject - */ -PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) -{ - var worldTransform = displayObject.worldTransform; - var global = this.global; - - // do a cheeky transform to get the mouse coords; - var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10); - // set the mouse coords... - return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) -} - -// constructor -PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Stage represents the root of the display tree. Everything connected to the stage is rendered - * - * @class Stage - * @extends DisplayObjectContainer - * @constructor - * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format - * like: 0xFFFFFF for white - */ -PIXI.Stage = function(backgroundColor) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create(); - - /** - * Whether or not the stage is interactive - * - * @property interactive - * @type Boolean - */ - this.interactive = true; - - /** - * The interaction manage for this stage, manages all interactive activity on the stage - * - * @property interactive - * @type InteractionManager - */ - this.interactionManager = new PIXI.InteractionManager(this); - - /** - * Whether the stage is dirty and needs to have interactions updated - * - * @property dirty - * @type Boolean - * @private - */ - this.dirty = true; - - this.__childrenAdded = []; - this.__childrenRemoved = []; - - //the stage is it's own stage - this.stage = this; - - //optimize hit detection a bit - this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); - - this.setBackgroundColor(backgroundColor); - this.worldVisible = true; -} - -// constructor -PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Stage.prototype.constructor = PIXI.Stage; - -/** - * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. - * This is useful for when you have other DOM elements ontop of the Canvas element. - * - * @method setInteractionDelegate - * @param domElement {DOMElement} This new domElement which will receive mouse/touch events - */ -PIXI.Stage.prototype.setInteractionDelegate = function(domElement) -{ - this.interactionManager.setTargetDomElement( domElement ); -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Stage.prototype.updateTransform = function() -{ - this.worldAlpha = 1; - this.vcount = PIXI.visibleCount; - - for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - -/** - * A polyfill for Function.prototype.bind - * - * @method bind - */ -if (typeof Function.prototype.bind != 'function') { - Function.prototype.bind = (function () { - var slice = Array.prototype.slice; - return function (thisArg) { - var target = this, boundArgs = slice.call(arguments, 1); - - if (typeof target != 'function') throw new TypeError(); - - function bound() { - var args = boundArgs.concat(slice.call(arguments)); - target.apply(this instanceof bound ? this : thisArg, args); - } - - bound.prototype = (function F(proto) { - proto && (F.prototype = proto); - if (!(this instanceof F)) return new F; - })(target.prototype); - - return bound; - }; - })(); -} - -/** - * A wrapper for ajax requests to be handled cross browser - * - * @class AjaxRequest - * @constructor - */ -var AjaxRequest = PIXI.AjaxRequest = function() -{ - var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE - - if (window.ActiveXObject) - { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) - for (var i=0; i>>>>>>>>") - console.log("_") - var safe = 0; - var tmp = item.first; - console.log(tmp); - - while(tmp._iNext) - { - safe++; - tmp = tmp._iNext; - console.log(tmp); - // console.log(tmp); - - if(safe > 100) - { - console.log("BREAK") - break - } - } -} - - - - - - -/** - * https://github.com/mrdoob/eventtarget.js/ - * THankS mr DOob! - */ - -/** - * Adds event emitter functionality to a class - * - * @class EventTarget - * @example - * function MyEmitter() { - * PIXI.EventTarget.call(this); //mixes in event target stuff - * } - * - * var em = new MyEmitter(); - * em.emit({ type: 'eventName', data: 'some data' }); - */ -PIXI.EventTarget = function () { - - var listeners = {}; - - this.addEventListener = this.on = function ( type, listener ) { - - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - } - - }; - - this.dispatchEvent = this.emit = function ( event ) { - - if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { - - return; - - } - - for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { - - listeners[ event.type ][ i ]( event ); - - } - - }; - - this.removeEventListener = this.off = function ( type, listener ) { - - var index = listeners[ type ].indexOf( listener ); - - if ( index !== - 1 ) { - - listeners[ type ].splice( index, 1 ); - - } - - }; - -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @method autoDetectRenderer - * @static - * @param width {Number} the width of the renderers view - * @param height {Number} the height of the renderers view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) - * - * antialias - */ -PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) -{ - if(!width)width = 800; - if(!height)height = 600; - - // BORROWED from Mr Doob (mrdoob.com) - var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); - - if(webgl) - { - var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); - webgl = !ie; - } - - //console.log(webgl); - if( webgl ) - { - return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); - } - - return new PIXI.CanvasRenderer(width, height, view, transparent); -}; - - - -/* - PolyK library - url: http://polyk.ivank.net - Released under MIT licence. - - Copyright (c) 2012 Ivan Kuckir - - 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. - - This is an amazing lib! - - slightly modified by mat groves (matgroves.com); -*/ - -PIXI.PolyK = {}; - -/** - * Triangulates shapes for webGL graphic fills - * - * @method Triangulate - * @namespace PolyK - * @constructor - */ -PIXI.PolyK.Triangulate = function(p) -{ - var sign = true; - - var n = p.length>>1; - if(n<3) return []; - var tgs = []; - var avl = []; - for(var i=0; i 3) - { - var i0 = avl[(i+0)%al]; - var i1 = avl[(i+1)%al]; - var i2 = avl[(i+2)%al]; - - var ax = p[2*i0], ay = p[2*i0+1]; - var bx = p[2*i1], by = p[2*i1+1]; - var cx = p[2*i2], cy = p[2*i2+1]; - - var earFound = false; - if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) - { - earFound = true; - for(var j=0; j 3*al) - { - // need to flip flip reverse it! - // reset! - if(sign) - { - var tgs = []; - avl = []; - for(var i=0; i= 0) && (v >= 0) && (u + v < 1); -} - -/** - * Checks if a shape is convex - * - * @class _convex - * @namespace PolyK - * @private - */ -PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) -{ - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.initDefaultShaders = function() -{ - PIXI.primitiveShader = new PIXI.PrimitiveShader(); - PIXI.primitiveShader.init(); - - PIXI.stripShader = new PIXI.StripShader(); - PIXI.stripShader.init(); - - PIXI.defaultShader = new PIXI.PixiShader(); - PIXI.defaultShader.init(); - - var gl = PIXI.gl; - var shaderProgram = PIXI.defaultShader.program; - - - gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.activatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.primitiveShader.program); - - gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - - gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); -} - -PIXI.deactivatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - - gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - -} - -PIXI.activateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.stripShader.program); - // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.deactivateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -/* - -SHADER COMPILER HELPERS -*/ - -PIXI.CompileVertexShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); -} - -PIXI.CompileFragmentShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); -} - -PIXI._CompileShader = function(gl, shaderSrc, shaderType) -{ - var src = shaderSrc.join("\n"); - var shader = gl.createShader(shaderType); - gl.shaderSource(shader, src); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - console.log(gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -} - - -PIXI.compileProgram = function(vertexSrc, fragmentSrc) -{ - var gl = PIXI.gl; - var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); - var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); - - var shaderProgram = gl.createProgram(); - - gl.attachShader(shaderProgram, vertexShader); - gl.attachShader(shaderProgram, fragmentShader); - gl.linkProgram(shaderProgram); - - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - console.log("Could not initialise shaders"); - } - - return shaderProgram; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PixiShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision lowp float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", - "}" - ]; - -} - -PIXI.PixiShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - // add those custom shaders! - for (var key in this.uniforms) - { - - // get the uniform locations.. - // program[key] = - this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); - - - } - - this.program = program; -} - -PIXI.PixiShader.prototype.syncUniforms = function() -{ - var gl = PIXI.gl; - - for (var key in this.uniforms) - { - //var - var type = this.uniforms[key].type; - - // need to grow this! - if(type == "f") - { - gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - if(type == "f2") - { - // console.log(this.program[key]) - gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); - } - else if(type == "f4") - { - // console.log(this.uniforms[key].value) - gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if(type == "mat4") - { - gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, false, this.uniforms[key].value); - } - else if(type == "sampler2D") - { - // first texture... - var texture = this.uniforms[key].value; - - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, texture.baseTexture._glTexture); - - gl.uniform1i(this.uniforms[key].uniformLocation, 1); - - // activate texture.. - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - } - } - -} - -PIXI.PixiShader.defaultVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "varying vec2 vTextureCoord;", - - "varying float vColor;", - - "const vec2 center = vec2(-1.0, 1.0);", - "void main(void) {", - "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" -]; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.StripShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform float alpha;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", - "gl_FragColor = gl_FragColor * alpha;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "varying vec2 vTextureCoord;", - "varying vec2 offsetVector;", - "varying float vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" - ]; -} - -PIXI.StripShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PrimitiveShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec4 vColor;", - "void main(void) {", - "gl_FragColor = vColor;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec4 aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "uniform float alpha;", - "varying vec4 vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vColor = aColor * alpha;", - "}" - ]; - -} - -PIXI.PrimitiveShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A set of functions used by the webGL renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.WebGLGraphics = function() -{ - -} - -/** - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param projection {Object} - */ -PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) -{ - var gl = PIXI.gl; - - if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, - buffer:gl.createBuffer(), - indexBuffer:gl.createBuffer()}; - - if(graphics.dirty) - { - graphics.dirty = false; - - if(graphics.clearDirty) - { - graphics.clearDirty = false; - - graphics._webGL.lastIndex = 0; - graphics._webGL.points = []; - graphics._webGL.indices = []; - - } - - PIXI.WebGLGraphics.updateGraphics(graphics); - } - - PIXI.activatePrimitiveShader(); - - // This could be speeded up fo sure! - var m = PIXI.mat3.clone(graphics.worldTransform); - - PIXI.mat3.transpose(m); - - // set the matrix transform for the - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); - - gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); - gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - - gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - - - gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); - - PIXI.deactivatePrimitiveShader(); - - - // return to default shader... -// PIXI.activateShader(PIXI.defaultShader); -} - -/** - * Updates the graphics object - * - * @static - * @private - * @method updateGraphics - * @param graphics {Graphics} - */ -PIXI.WebGLGraphics.updateGraphics = function(graphics) -{ - for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - - if(data.type == PIXI.Graphics.POLY) - { - if(data.fill) - { - if(data.points.length>3) - PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); - } - - if(data.lineWidth > 0) - { - PIXI.WebGLGraphics.buildLine(data, graphics._webGL); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); - } - else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) - { - PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); - } - }; - - graphics._webGL.lastIndex = graphics.graphicsData.length; - - var gl = PIXI.gl; - - graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); - - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); - - graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); -} - -/** - * Builds a rectangle to draw - * - * @static - * @private - * @method buildRectangle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vertPos = verts.length/6; - - // start - verts.push(x, y); - verts.push(r, g, b, alpha); - - verts.push(x + width, y); - verts.push(r, g, b, alpha); - - verts.push(x , y + height); - verts.push(r, g, b, alpha); - - verts.push(x + width, y + height); - verts.push(r, g, b, alpha); - - // insert 2 dead triangles.. - indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) - } - - if(graphicsData.lineWidth) - { - graphicsData.points = [x, y, - x + width, y, - x + width, y + height, - x, y + height, - x, y]; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a circle to draw - * - * @static - * @private - * @method buildCircle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - var totalSegs = 40; - var seg = (Math.PI * 2) / totalSegs ; - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - indices.push(vecPos); - - for (var i=0; i < totalSegs + 1 ; i++) - { - verts.push(x,y, r, g, b, alpha); - - verts.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height, - r, g, b, alpha); - - indices.push(vecPos++, vecPos++); - }; - - indices.push(vecPos-1); - } - - if(graphicsData.lineWidth) - { - graphicsData.points = []; - - for (var i=0; i < totalSegs + 1; i++) - { - graphicsData.points.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height) - }; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a line to draw - * - * @static - * @private - * @method buildLine - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) -{ - // TODO OPTIMISE! - - var wrap = true; - var points = graphicsData.points; - if(points.length == 0)return; - - // if the line width is an odd number add 0.5 to align to a whole pixel - if(graphicsData.lineWidth%2) - { - for (var i = 0; i < points.length; i++) { - points[i] += 0.5; - }; - } - - // get first and last point.. figure out the middle! - var firstPoint = new PIXI.Point( points[0], points[1] ); - var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - // if the first point is the last point - goona have issues :) - if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) - { - points.pop(); - points.pop(); - - lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; - var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - - points.unshift(midPointX, midPointY); - points.push(midPointX, midPointY) - } - - var verts = webGLData.points; - var indices = webGLData.indices; - var length = points.length / 2; - var indexCount = points.length; - var indexStart = verts.length/6; - - // DRAW the Line - var width = graphicsData.lineWidth / 2; - - // sort color - var color = HEXtoRGB(graphicsData.lineColor); - var alpha = graphicsData.lineAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var p1x, p1y, p2x, p2y, p3x, p3y; - var perpx, perpy, perp2x, perp2y, perp3x, perp3y; - var ipx, ipy; - var a1, b1, c1, a2, b2, c2; - var denom, pdist, dist; - - p1x = points[0]; - p1y = points[1]; - - p2x = points[2]; - p2y = points[3]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - // start - verts.push(p1x - perpx , p1y - perpy, - r, g, b, alpha); - - verts.push(p1x + perpx , p1y + perpy, - r, g, b, alpha); - - for (var i = 1; i < length-1; i++) - { - p1x = points[(i-1)*2]; - p1y = points[(i-1)*2 + 1]; - - p2x = points[(i)*2] - p2y = points[(i)*2 + 1] - - p3x = points[(i+1)*2]; - p3y = points[(i+1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - perp2x = -(p2y - p3y); - perp2y = p2x - p3x; - - dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); - perp2x /= dist; - perp2y /= dist; - perp2x *= width; - perp2y *= width; - - a1 = (-perpy + p1y) - (-perpy + p2y); - b1 = (-perpx + p2x) - (-perpx + p1x); - c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); - a2 = (-perp2y + p3y) - (-perp2y + p2y); - b2 = (-perp2x + p2x) - (-perp2x + p3x); - c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - - denom = a1*b2 - a2*b1; - - if(Math.abs(denom) < 0.1 ) - { - - denom+=10.1; - verts.push(p2x - perpx , p2y - perpy, - r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy, - r, g, b, alpha); - - continue; - } - - px = (b1*c2 - b2*c1)/denom; - py = (a2*c1 - a1*c2)/denom; - - - pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - - - if(pdist > 140 * 140) - { - perp3x = perpx - perp2x; - perp3y = perpy - perp2y; - - dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); - perp3x /= dist; - perp3y /= dist; - perp3x *= width; - perp3y *= width; - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x + perp3x, p2y +perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - indexCount++; - } - else - { - - verts.push(px , py); - verts.push(r, g, b, alpha); - - verts.push(p2x - (px-p2x), p2y - (py - p2y)); - verts.push(r, g, b, alpha); - } - } - - p1x = points[(length-2)*2] - p1y = points[(length-2)*2 + 1] - - p2x = points[(length-1)*2] - p2y = points[(length-1)*2 + 1] - - perpx = -(p1y - p2y) - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - verts.push(p2x - perpx , p2y - perpy) - verts.push(r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy) - verts.push(r, g, b, alpha); - - indices.push(indexStart); - - for (var i=0; i < indexCount; i++) - { - indices.push(indexStart++); - }; - - indices.push(indexStart-1); -} - -/** - * Builds a polygon to draw - * - * @static - * @private - * @method buildPoly - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) -{ - var points = graphicsData.points; - if(points.length < 6)return; - - // get first and last point.. figure out the middle! - var verts = webGLData.points; - var indices = webGLData.indices; - - var length = points.length / 2; - - // sort color - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var triangles = PIXI.PolyK.Triangulate(points); - - var vertPos = verts.length / 6; - - for (var i=0; i < triangles.length; i+=3) - { - indices.push(triangles[i] + vertPos); - indices.push(triangles[i] + vertPos); - indices.push(triangles[i+1] + vertPos); - indices.push(triangles[i+2] +vertPos); - indices.push(triangles[i+2] + vertPos); - }; - - for (var i = 0; i < length; i++) - { - verts.push(points[i * 2], points[i * 2 + 1], - r, g, b, alpha); - }; -} - -function HEXtoRGB(hex) { - return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); - -// an instance of the gl context.. -// only one at the moment :/ -PIXI.gl; - -/** - * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer - * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. - * So no need for Sprite Batch's or Sprite Cloud's - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class WebGLRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) - * - */ -PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) -{ - // do a catch.. only 1 webGL renderer.. - - this.transparent = !!transparent; - - this.width = width || 800; - this.height = height || 600; - - this.view = view || document.createElement( 'canvas' ); - this.view.width = this.width; - this.view.height = this.height; - - // deal with losing context.. - var scope = this; - this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) - this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) - - this.batchs = []; - - var options = { - alpha: this.transparent, - antialias:!!antialias, // SPEED UP?? - premultipliedAlpha:false, - stencil:true - } - - //try 'experimental-webgl' - try { - PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); - } catch (e) { - //try 'webgl' - try { - PIXI.gl = this.gl = this.view.getContext("webgl", options); - } catch (e) { - // fail, not able to get a context - throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); - } - } - - PIXI.initDefaultShaders(); - - - - - // PIXI.activateDefaultShader(); - - var gl = this.gl; - - gl.useProgram(PIXI.defaultShader.program); - - - PIXI.WebGLRenderer.gl = gl; - - this.batch = new PIXI.WebGLBatch(gl); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, this.transparent); - - PIXI.projection = new PIXI.Point(400, 300); - PIXI.offset = new PIXI.Point(0, 0); - - // TODO remove thease globals.. - - this.resize(this.width, this.height); - this.contextLost = false; - - //PIXI.pushShader(PIXI.defaultShader); - - this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); - // this.stageRenderGroup. = this.transparent -} - -// constructor -PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; - -/** - * Gets a new WebGLBatch from the pool - * - * @static - * @method getBatch - * @return {WebGLBatch} - * @private - */ -PIXI.WebGLRenderer.getBatch = function() -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * Puts a batch back into the pool - * - * @static - * @method returnBatch - * @param batch {WebGLBatch} The batch to return - * @private - */ -PIXI.WebGLRenderer.returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * Renders the stage to its webGL view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.WebGLRenderer.prototype.render = function(stage) -{ - if(this.contextLost)return; - - - // if rendering a new stage clear the batchs.. - if(this.__stage !== stage) - { - // TODO make this work - // dont think this is needed any more? - this.__stage = stage; - this.stageRenderGroup.setRenderable(stage); - } - - // update any textures - PIXI.WebGLRenderer.updateTextures(); - - // update the scene graph - PIXI.visibleCount++; - stage.updateTransform(); - - var gl = this.gl; - - // -- Does this need to be set every frame? -- // - gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); - gl.clear(gl.COLOR_BUFFER_BIT); - - // HACK TO TEST - - this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - this.stageRenderGroup.render(PIXI.projection); - - // interaction - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // after rendering lets confirm all frames that have been uodated.. - if(PIXI.Texture.frameUpdates.length > 0) - { - for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) - { - PIXI.Texture.frameUpdates[i].updateFrame = false; - }; - - PIXI.Texture.frameUpdates = []; - } -} - -/** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - //TODO break this out into a texture manager... - for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; -} - -/** - * Updates a loaded webgl texture - * - * @static - * @method updateTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.updateTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(!texture._glTexture) - { - texture._glTexture = gl.createTexture(); - } - - if(texture.hasLoaded) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - } -} - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(texture._glTexture) - { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); - } -} - -/** - * resizes the webGL view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the webGL view - * @param height {Number} the new height of the webGL view - */ -PIXI.WebGLRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; - - this.gl.viewport(0, 0, this.width, this.height); - - //var projectionMatrix = this.projectionMatrix; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - //PIXI.size.x = this.width/2; - //PIXI.size.y = -this.height/2; - -// projectionMatrix[0] = 2/this.width; -// projectionMatrix[5] = -2/this.height; -// projectionMatrix[12] = -1; -// projectionMatrix[13] = 1; -} - -/** - * Handles a lost webgl context - * - * @method handleContextLost - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextLost = function(event) -{ - event.preventDefault(); - this.contextLost = true; -} - -/** - * Handles a restored webgl context - * - * @method handleContextRestored - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) -{ - this.gl = this.view.getContext("experimental-webgl", { - alpha: true - }); - - this.initShaders(); - - for(var key in PIXI.TextureCache) - { - var texture = PIXI.TextureCache[key].baseTexture; - texture._glTexture = null; - PIXI.WebGLRenderer.updateTexture(texture); - }; - - for (var i=0; i < this.batchs.length; i++) - { - this.batchs[i].restoreLostContext(this.gl)// - this.batchs[i].dirty = true; - }; - - PIXI._restoreBatchs(this.gl); - - this.contextLost = false; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._batchs = []; - -/** - * @private - */ -PIXI._getBatch = function(gl) -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * @private - */ -PIXI._returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * @private - */ -PIXI._restoreBatchs = function(gl) -{ - for (var i=0; i < PIXI._batchs.length; i++) - { - PIXI._batchs[i].restoreLostContext(gl); - }; -} - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. - * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites - * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled - * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @constructor - * @param gl {WebGLContext} an instance of the webGL context - */ -PIXI.WebGLBatch = function(gl) -{ - this.gl = gl; - - this.size = 0; - - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - this.blendMode = PIXI.blendModes.NORMAL; - this.dynamicSize = 1; -} - -// constructor -PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; - -/** - * Cleans the batch so that is can be returned to an object pool and reused - * - * @method clean - */ -PIXI.WebGLBatch.prototype.clean = function() -{ - this.verticies = []; - this.uvs = []; - this.indices = []; - this.colors = []; - this.dynamicSize = 1; - this.texture = null; - this.last = null; - this.size = 0; - this.head; - this.tail; -} - -/** - * Recreates the buffers in the event of a context loss - * - * @method restoreLostContext - * @param gl {WebGLContext} - */ -PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) -{ - this.gl = gl; - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); -} - -/** - * inits the batch's texture and blend mode based if the supplied sprite - * - * @method init - * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with - * the same base texture and blend mode will be allowed to be added to this batch - */ -PIXI.WebGLBatch.prototype.init = function(sprite) -{ - sprite.batch = this; - this.dirty = true; - this.blendMode = sprite.blendMode; - this.texture = sprite.texture.baseTexture; - this.head = sprite; - this.tail = sprite; - this.size = 1; - - this.growBatch(); -} - -/** - * inserts a sprite before the specified sprite - * - * @method insertBefore - * @param sprite {Sprite} the sprite to be added - * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite - */ -PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - var tempPrev = nextSprite.__prev; - nextSprite.__prev = sprite; - sprite.__next = nextSprite; - - if(tempPrev) - { - sprite.__prev = tempPrev; - tempPrev.__next = sprite; - } - else - { - this.head = sprite; - } -} - -/** - * inserts a sprite after the specified sprite - * - * @method insertAfter - * @param sprite {Sprite} the sprite to be added - * @param previousSprite {Sprite} the first sprite will be inserted after this sprite - */ -PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - - var tempNext = previousSprite.__next; - previousSprite.__next = sprite; - sprite.__prev = previousSprite; - - if(tempNext) - { - sprite.__next = tempNext; - tempNext.__prev = sprite; - } - else - { - this.tail = sprite - } -} - -/** - * removes a sprite from the batch - * - * @method remove - * @param sprite {Sprite} the sprite to be removed - */ -PIXI.WebGLBatch.prototype.remove = function(sprite) -{ - this.size--; - - if(this.size == 0) - { - sprite.batch = null; - sprite.__prev = null; - sprite.__next = null; - return; - } - - if(sprite.__prev) - { - sprite.__prev.__next = sprite.__next; - } - else - { - this.head = sprite.__next; - this.head.__prev = null; - } - - if(sprite.__next) - { - sprite.__next.__prev = sprite.__prev; - } - else - { - this.tail = sprite.__prev; - this.tail.__next = null - } - - sprite.batch = null; - sprite.__next = null; - sprite.__prev = null; - this.dirty = true; -} - -/** - * Splits the batch into two with the specified sprite being the start of the new batch. - * - * @method split - * @param sprite {Sprite} the sprite that indicates where the batch should be split - * @return {WebGLBatch} the new batch - */ -PIXI.WebGLBatch.prototype.split = function(sprite) -{ - this.dirty = true; - - var batch = new PIXI.WebGLBatch(this.gl); - batch.init(sprite); - batch.texture = this.texture; - batch.tail = this.tail; - - this.tail = sprite.__prev; - this.tail.__next = null; - - sprite.__prev = null; - // return a splite batch! - - // TODO this size is wrong! - // need to recalculate :/ problem with a linked list! - // unless it gets calculated in the "clean"? - - // need to loop through items as there is no way to know the length on a linked list :/ - var tempSize = 0; - while(sprite) - { - tempSize++; - sprite.batch = batch; - sprite = sprite.__next; - } - - batch.size = tempSize; - this.size -= tempSize; - - return batch; -} - -/** - * Merges two batchs together - * - * @method merge - * @param batch {WebGLBatch} the batch that will be merged - */ -PIXI.WebGLBatch.prototype.merge = function(batch) -{ - this.dirty = true; - - this.tail.__next = batch.head; - batch.head.__prev = this.tail; - - this.size += batch.size; - - this.tail = batch.tail; - - var sprite = batch.head; - while(sprite) - { - sprite.batch = this; - sprite = sprite.__next; - } -} - -/** - * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this - * function is used to increase the size of the batch. It also creates a little extra room so - * that the batch does not need to be resized every time a sprite is added - * - * @method growBatch - */ -PIXI.WebGLBatch.prototype.growBatch = function() -{ - var gl = this.gl; - if( this.size == 1) - { - this.dynamicSize = 1; - } - else - { - this.dynamicSize = this.size * 1.5 - } - // grow verts - this.verticies = new Float32Array(this.dynamicSize * 8); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - - this.uvs = new Float32Array( this.dynamicSize * 8 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); - - this.dirtyUVS = true; - - this.colors = new Float32Array( this.dynamicSize * 4 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); - - this.dirtyColors = true; - - this.indices = new Uint16Array(this.dynamicSize * 6); - var length = this.indices.length/6; - - for (var i=0; i < length; i++) - { - var index2 = i * 6; - var index3 = i * 4; - this.indices[index2 + 0] = index3 + 0; - this.indices[index2 + 1] = index3 + 1; - this.indices[index2 + 2] = index3 + 2; - this.indices[index2 + 3] = index3 + 0; - this.indices[index2 + 4] = index3 + 2; - this.indices[index2 + 5] = index3 + 3; - }; - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); -} - -/** - * Refresh's all the data in the batch and sync's it with the webGL buffers - * - * @method refresh - */ -PIXI.WebGLBatch.prototype.refresh = function() -{ - var gl = this.gl; - - if (this.dynamicSize < this.size) - { - this.growBatch(); - } - - var indexRun = 0; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; - var a, b, c, d, tx, ty; - - var displayObject = this.head; - - while(displayObject) - { - index = indexRun * 8; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - this.uvs[index + 0] = frame.x / tw; - this.uvs[index +1] = frame.y / th; - - this.uvs[index +2] = (frame.x + frame.width) / tw; - this.uvs[index +3] = frame.y / th; - - this.uvs[index +4] = (frame.x + frame.width) / tw; - this.uvs[index +5] = (frame.y + frame.height) / th; - - this.uvs[index +6] = frame.x / tw; - this.uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - - colorIndex = indexRun * 4; - this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; - - displayObject = displayObject.__next; - - indexRun ++; - } - - this.dirtyUVS = true; - this.dirtyColors = true; -} - -/** - * Updates all the relevant geometry and uploads the data to the GPU - * - * @method update - */ -PIXI.WebGLBatch.prototype.update = function() -{ - var gl = this.gl; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 - - var a, b, c, d, tx, ty; - - var indexRun = 0; - - var displayObject = this.head; - var verticies = this.verticies; - var uvs = this.uvs; - var colors = this.colors; - - while(displayObject) - { - if(displayObject.vcount === PIXI.visibleCount) - { - width = displayObject.texture.frame.width; - height = displayObject.texture.frame.height; - - // TODO trim?? - aX = displayObject.anchor.x;// - displayObject.texture.trim.x - aY = displayObject.anchor.y; //- displayObject.texture.trim.y - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - index = indexRun * 8; - - worldTransform = displayObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - verticies[index + 0 ] = a * w1 + c * h1 + tx; - verticies[index + 1 ] = d * h1 + b * w1 + ty; - - verticies[index + 2 ] = a * w0 + c * h1 + tx; - verticies[index + 3 ] = d * h1 + b * w0 + ty; - - verticies[index + 4 ] = a * w0 + c * h0 + tx; - verticies[index + 5 ] = d * h0 + b * w0 + ty; - - verticies[index + 6] = a * w1 + c * h0 + tx; - verticies[index + 7] = d * h0 + b * w1 + ty; - - if(displayObject.updateFrame || displayObject.texture.updateFrame) - { - this.dirtyUVS = true; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - uvs[index + 0] = frame.x / tw; - uvs[index +1] = frame.y / th; - - uvs[index +2] = (frame.x + frame.width) / tw; - uvs[index +3] = frame.y / th; - - uvs[index +4] = (frame.x + frame.width) / tw; - uvs[index +5] = (frame.y + frame.height) / th; - - uvs[index +6] = frame.x / tw; - uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - } - - // TODO this probably could do with some optimisation.... - if(displayObject.cacheAlpha != displayObject.worldAlpha) - { - displayObject.cacheAlpha = displayObject.worldAlpha; - - var colorIndex = indexRun * 4; - colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; - this.dirtyColors = true; - } - } - else - { - index = indexRun * 8; - - verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; - } - - indexRun++; - displayObject = displayObject.__next; - } -} - -/** - * Draws the batch to the frame buffer - * - * @method render - */ -PIXI.WebGLBatch.prototype.render = function(start, end) -{ - start = start || 0; - - if(end == undefined)end = this.size; - - if(this.dirty) - { - this.refresh(); - this.dirty = false; - } - - if (this.size == 0)return; - - this.update(); - var gl = this.gl; - - //TODO optimize this! - - var shaderProgram = PIXI.defaultShader; - - //gl.useProgram(shaderProgram); - - // update the verts.. - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - // ok.. - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) - gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - // update the uvs - //var isDefault = (shaderProgram == PIXI.shaderProgram) - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - if(this.dirtyUVS) - { - this.dirtyUVS = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); - } - - gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); - - // update color! - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - - if(this.dirtyColors) - { - this.dirtyColors = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); - } - - gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - var len = end - start; - - // DRAW THAT this! - gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be - * grouped into a batch. All the sprites in a batch can then be drawn in one go by the - * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch - * even if the batch only contains one sprite. Batching is handled automatically by the - * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @contructor - * @param gl {WebGLContext} An instance of the webGL context - */ -PIXI.WebGLRenderGroup = function(gl, transparent) -{ - this.gl = gl; - this.root; - - this.backgroundColor; - this.transparent = transparent == undefined ? true : transparent; - - this.batchs = []; - this.toRemove = []; - console.log(this.transparent) - this.filterManager = new PIXI.WebGLFilterManager(this.transparent); -} - -// constructor -PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; - -/** - * Add a display object to the webgl renderer - * - * @method setRenderable - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) -{ - // has this changed?? - if(this.root)this.removeDisplayObjectAndChildren(this.root); - - displayObject.worldVisible = displayObject.visible; - - // soooooo // - // to check if any batchs exist already?? - - // TODO what if its already has an object? should remove it - this.root = displayObject; - this.addDisplayObjectAndChildren(displayObject); -} - -/** - * Renders the stage to its webgl view - * - * @method render - * @param projection {Object} - */ -PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - - var gl = this.gl; - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - // will render all the elements in the group - var renderable; - - for (var i=0; i < this.batchs.length; i++) - { - - renderable = this.batchs[i]; - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - continue; - } - - // render special - this.renderSpecial(renderable, projection); - } - -} - -/** - * Renders a specific displayObject - * - * @method renderSpecific - * @param displayObject {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - var gl = this.gl; - - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - // to do! - // render part of the scene... - - var startIndex; - var startBatchIndex; - - var endIndex; - var endBatchIndex; - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.first; - while(nextRenderable._iNext) - { - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - nextRenderable = nextRenderable._iNext; - } - var startBatch = nextRenderable.batch; - //console.log(nextRenderable); - - //console.log(renderable) - if(nextRenderable instanceof PIXI.Sprite) - { - startBatch = nextRenderable.batch; - - var head = startBatch.head; - var next = head; - - // ok now we have the batch.. need to find the start index! - if(head == nextRenderable) - { - startIndex = 0; - } - else - { - startIndex = 1; - - while(head.__next != nextRenderable) - { - startIndex++; - head = head.__next; - } - } - } - else - { - startBatch = nextRenderable; - } - - // Get the LAST renderable object - var lastRenderable = displayObject.last; - while(lastRenderable._iPrev) - { - if(lastRenderable.renderable && lastRenderable.__renderGroup)break; - lastRenderable = lastRenderable._iNext; - } - - if(lastRenderable instanceof PIXI.Sprite) - { - endBatch = lastRenderable.batch; - - var head = endBatch.head; - - if(head == lastRenderable) - { - endIndex = 0; - } - else - { - endIndex = 1; - - while(head.__next != lastRenderable) - { - endIndex++; - head = head.__next; - } - } - } - else - { - endBatch = lastRenderable; - } - - //console.log(endBatch); - // TODO - need to fold this up a bit! - - if(startBatch == endBatch) - { - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex, endIndex+1); - } - else - { - this.renderSpecial(startBatch, projection); - } - return; - } - - // now we have first and last! - startBatchIndex = this.batchs.indexOf(startBatch); - endBatchIndex = this.batchs.indexOf(endBatch); - - // DO the first batch - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex); - } - else - { - this.renderSpecial(startBatch, projection); - } - - // DO the middle batchs.. - for (var i=startBatchIndex+1; i < endBatchIndex; i++) - { - renderable = this.batchs[i]; - - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - } - else - { - this.renderSpecial(renderable, projection); - } - } - - // DO the last batch.. - if(endBatch instanceof PIXI.WebGLBatch) - { - endBatch.render(0, endIndex+1); - } - else - { - this.renderSpecial(endBatch, projection); - } -} - -/** - * Renders a specific renderable - * - * @method renderSpecial - * @param renderable {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) -{ - - var worldVisible = renderable.vcount === PIXI.visibleCount - - - if(renderable instanceof PIXI.TilingSprite) - { - if(worldVisible)this.renderTilingSprite(renderable, projection); - } - else if(renderable instanceof PIXI.Strip) - { - if(worldVisible)this.renderStrip(renderable, projection); - } - else if(renderable instanceof PIXI.CustomRenderable) - { - if(worldVisible) renderable.renderWebGL(this, projection); - } - else if(renderable instanceof PIXI.Graphics) - { - if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); - } - else if(renderable instanceof PIXI.FilterBlock) - { - this.handleFilterBlock(renderable, projection); - } -} - -flip = false; -var maskStack = []; -var maskPosition = 0; - -//var usedMaskStack = []; - -PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) -{ - /* - * for now only masks are supported.. - */ - var gl = PIXI.gl; - - if(filterBlock.open) - { - if(filterBlock.data instanceof Array) - { - this.filterManager.pushFilter(filterBlock); - // ok so.. - - } - else - { - maskPosition++; - - maskStack.push(filterBlock) - - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - - PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - } - else - { - if(filterBlock.data instanceof Array) - { - this.filterManager.popFilter(); - } - else - { - var maskData = maskStack.pop(filterBlock) - - - if(maskData) - { - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - - PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - }; - - gl.disable(gl.STENCIL_TEST); - } - } -} - -/** - * Updates a webgl texture - * - * @method updateTexture - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) -{ - - // TODO definitely can optimse this function.. - - this.removeObject(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = displayObject.first; - while(previousRenderable != this.root) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - this.insertObject(displayObject, previousRenderable, nextRenderable); -} - -/** - * Adds filter blocks - * - * @method addFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) -{ - start.__renderGroup = this; - end.__renderGroup = this; - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = start; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - this.insertAfter(start, previousRenderable); - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var previousRenderable2 = end; - while(previousRenderable2 != this.root.first) - { - previousRenderable2 = previousRenderable2._iPrev; - if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; - } - this.insertAfter(end, previousRenderable2); -} - -/** - * Remove filter blocks - * - * @method removeFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) -{ - this.removeObject(start); - this.removeObject(end); -} - -/** - * Adds a display object and children to the webgl context - * - * @method addDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - - var previousRenderable = displayObject.first; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - // one the display object hits this. we can break the loop - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - do - { - tempObject.__renderGroup = this; - - if(tempObject.renderable) - { - - this.insertObject(tempObject, previousRenderable, nextRenderable); - previousRenderable = tempObject; - } - - tempObject = tempObject._iNext; - } - while(tempObject != testObject) -} - -/** - * Removes a display object and children to the webgl context - * - * @method removeDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup != this)return; - -// var displayObject = displayObject.first; - var lastObject = displayObject.last; - do - { - displayObject.__renderGroup = null; - if(displayObject.renderable)this.removeObject(displayObject); - displayObject = displayObject._iNext; - } - while(displayObject) -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertObject - * @param displayObject {DisplayObject} - * @param previousObject {DisplayObject} - * @param nextObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) -{ - // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED - var previousSprite = previousObject; - var nextSprite = nextObject; - - /* - * so now we have the next renderable and the previous renderable - * - */ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch - var nextBatch - - if(previousSprite instanceof PIXI.Sprite) - { - previousBatch = previousSprite.batch; - if(previousBatch) - { - if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) - { - previousBatch.insertAfter(displayObject, previousSprite); - return; - } - } - } - else - { - // TODO reword! - previousBatch = previousSprite; - } - - if(nextSprite) - { - if(nextSprite instanceof PIXI.Sprite) - { - nextBatch = nextSprite.batch; - - //batch may not exist if item was added to the display list but not to the webGL - if(nextBatch) - { - if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) - { - nextBatch.insertBefore(displayObject, nextSprite); - return; - } - else - { - if(nextBatch == previousBatch) - { - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(nextSprite); - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var batch = PIXI.WebGLRenderer.getBatch(); - - var index = this.batchs.indexOf( previousBatch ); - batch.init(displayObject); - this.batchs.splice(index+1, 0, batch, splitBatch); - - return; - } - } - } - } - else - { - // TODO re-word! - - nextBatch = nextSprite; - } - } - - /* - * looks like it does not belong to any batch! - * but is also not intersecting one.. - * time to create anew one! - */ - - var batch = PIXI.WebGLRenderer.getBatch(); - batch.init(displayObject); - - if(previousBatch) // if this is invalid it means - { - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, batch); - } - else - { - this.batchs.push(batch); - } - - return; - } - else if(displayObject instanceof PIXI.TilingSprite) - { - - // add to a batch!! - this.initTilingSprite(displayObject); - // this.batchs.push(displayObject); - - } - else if(displayObject instanceof PIXI.Strip) - { - // add to a batch!! - this.initStrip(displayObject); - // this.batchs.push(displayObject); - } - else if(displayObject)// instanceof PIXI.Graphics) - { - //displayObject.initWebGL(this); - - // add to a batch!! - //this.initStrip(displayObject); - //this.batchs.push(displayObject); - } - - this.insertAfter(displayObject, previousSprite); - - // insert and SPLIT! - -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertAfter - * @param item {DisplayObject} - * @param displayObject {DisplayObject} The object to insert - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) -{ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch = displayObject.batch; - - if(previousBatch) - { - // so this object is in a batch! - - // is it not? need to split the batch - if(previousBatch.tail == displayObject) - { - // is it tail? insert in to batchs - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item); - } - else - { - // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // - - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(displayObject.__next); - - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item, splitBatch); - } - } - else - { - this.batchs.push(item); - } - } - else - { - var index = this.batchs.indexOf( displayObject ); - this.batchs.splice(index+1, 0, item); - } -} - -/** - * Removes a displayObject from the linked list - * - * @method removeObject - * @param displayObject {DisplayObject} The object to remove - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) -{ - // loop through children.. - // display object // - - // add a child from the render group.. - // remove it and all its children! - //displayObject.cacheVisible = false;//displayObject.visible; - - /* - * removing is a lot quicker.. - * - */ - var batchToRemove; - - if(displayObject instanceof PIXI.Sprite) - { - // should always have a batch! - var batch = displayObject.batch; - if(!batch)return; // this means the display list has been altered befre rendering - - batch.remove(displayObject); - - if(batch.size==0) - { - batchToRemove = batch; - } - } - else - { - batchToRemove = displayObject; - } - - /* - * Looks like there is somthing that needs removing! - */ - if(batchToRemove) - { - var index = this.batchs.indexOf( batchToRemove ); - if(index == -1)return;// this means it was added then removed before rendered - - // ok so.. check to see if you adjacent batchs should be joined. - // TODO may optimise? - if(index == 0 || index == this.batchs.length-1) - { - // wha - eva! just get of the empty batch! - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - - return; - } - - if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) - { - if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) - { - //console.log("MERGE") - this.batchs[index-1].merge(this.batchs[index+1]); - - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); - this.batchs.splice(index, 2); - return; - } - } - - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - } -} - - -/** - * Initializes a tiling sprite - * - * @method initTilingSprite - * @param sprite {TilingSprite} The tiling sprite to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) -{ - var gl = this.gl; - - // make the texture tilable.. - - sprite.verticies = new Float32Array([0, 0, - sprite.width, 0, - sprite.width, sprite.height, - 0, sprite.height]); - - sprite.uvs = new Float32Array([0, 0, - 1, 0, - 1, 1, - 0, 1]); - - sprite.colors = new Float32Array([1,1,1,1]); - - sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); - - sprite._vertexBuffer = gl.createBuffer(); - sprite._indexBuffer = gl.createBuffer(); - sprite._uvBuffer = gl.createBuffer(); - sprite._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); - -// return ( (x > 0) && ((x & (x - 1)) == 0) ); - - if(sprite.texture.baseTexture._glTexture) - { - gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - sprite.texture.baseTexture._powerOf2 = true; - } - else - { - sprite.texture.baseTexture._powerOf2 = true; - } -} - -/** - * Renders a Strip - * - * @method renderStrip - * @param strip {Strip} The strip to render - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) -{ - var gl = this.gl; - - PIXI.activateStripShader(); - - var shader = PIXI.stripShader; - - var program = shader.program; - - var m = PIXI.mat3.clone(strip.worldTransform); - - PIXI.mat3.transpose(m); - -// console.log(projection) - // set the matrix transform for the - gl.uniformMatrix3fv(shader.translationMatrix, false, m); - gl.uniform2f(shader.projectionVector, projection.x, projection.y); - gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(shader.alpha, strip.worldAlpha); - - /* - if(strip.blendMode == PIXI.blendModes.NORMAL) - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - } - else - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); - } - */ - - //console.log("!!") - if(!strip.dirty) - { - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - } - else - { - strip.dirty = false; - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - // console.log(strip.texture.baseTexture._glTexture) - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); - - } - - gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - - PIXI.deactivateStripShader(); - //gl.useProgram(PIXI.currentProgram); -} - -/** - * Renders a TilingSprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tiling sprite to render - * @param projectionMatrix {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) -{ - var gl = this.gl; - - - var shaderProgram = PIXI.shaderProgram; - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - var offsetX = tilePosition.x/sprite.texture.baseTexture.width; - var offsetY = tilePosition.y/sprite.texture.baseTexture.height; - - var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; - var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; - - sprite.uvs[0] = 0 - offsetX; - sprite.uvs[1] = 0 - offsetY; - - sprite.uvs[2] = (1 * scaleX) -offsetX; - sprite.uvs[3] = 0 - offsetY; - - sprite.uvs[4] = (1 *scaleX) - offsetX; - sprite.uvs[5] = (1 *scaleY) - offsetY; - - sprite.uvs[6] = 0 - offsetX; - sprite.uvs[7] = (1 *scaleY) - offsetY; - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) - - this.renderStrip(sprite, projectionMatrix); -} - -/** - * Initializes a strip to be rendered - * - * @method initStrip - * @param strip {Strip} The strip to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) -{ - // build the strip! - var gl = this.gl; - var shaderProgram = this.shaderProgram; - - strip._vertexBuffer = gl.createBuffer(); - strip._indexBuffer = gl.createBuffer(); - strip._uvBuffer = gl.createBuffer(); - strip._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); - - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.WebGLFilterManager = function(transparent) -{ - this.transparent = transparent; - - this.filterStack = []; - this.texturePool = []; - - this.offsetX = 0; - this.offsetY = 0; - - this.initShaderBuffers(); -} - -// API - -PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) -{ - this.width = projection.x * 2; - this.height = -projection.y * 2; - this.buffer = buffer; -} - -PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) -{ - var gl = PIXI.gl; - - // filter program - // OPTIMISATION - the first filter is free if its a simple color change? - this.filterStack.push(filterBlock); - - var filter = filterBlock.filterPasses[0]; - - - - this.offsetX += filterBlock.target.filterArea.x; - this.offsetY += filterBlock.target.filterArea.y; - - - - - - var texture = this.texturePool.pop(); - if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); - - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - this.getBounds(filterBlock.target); - - // addpadding? - //displayObject.filterArea.x - - var filterArea = filterBlock.target.filterArea; - - var padidng = filter.padding; - filterArea.x -= padidng; - filterArea.y -= padidng; - filterArea.width += padidng * 2; - filterArea.height += padidng * 2; - - // cap filter to screen size.. - if(filterArea.x < 0)filterArea.x = 0; - if(filterArea.width > this.width)filterArea.width = this.width; - if(filterArea.y < 0)filterArea.y = 0; - if(filterArea.height > this.height)filterArea.height = this.height; - - - //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); - - // console.log(filterArea) - // set view port - gl.viewport(0, 0, filterArea.width, filterArea.height); - - PIXI.projection.x = filterArea.width/2; - PIXI.projection.y = -filterArea.height/2; - - PIXI.offset.x = -filterArea.x; - PIXI.offset.y = -filterArea.y; - - //console.log(PIXI.defaultShader.projectionVector) - // update projection - gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); - //PIXI.primitiveProgram - - gl.colorMask(true, true, true, true); - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - //filter.texture = texture; - filterBlock._glFilterTexture = texture; - - //console.log("PUSH") -} - - -PIXI.WebGLFilterManager.prototype.popFilter = function() -{ - - var gl = PIXI.gl; - - var filterBlock = this.filterStack.pop(); - - - - var filterArea = filterBlock.target.filterArea; - - var texture = filterBlock._glFilterTexture; - - if(filterBlock.filterPasses.length > 1) - { - gl.viewport(0, 0, filterArea.width, filterArea.height); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = 0; - this.vertexArray[1] = filterArea.height; - - this.vertexArray[2] = filterArea.width; - this.vertexArray[3] = filterArea.height; - - this.vertexArray[4] = 0; - this.vertexArray[5] = 0; - - this.vertexArray[6] = filterArea.width; - this.vertexArray[7] = 0; - - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - // nnow set the uvs.. - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - var inputTexture = texture; - var outputTexture = this.texturePool.pop(); - if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); - - // need to clear this FBO as it may have some left over elements from a prvious filter. - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.disable(gl.BLEND); - - for (var i = 0; i < filterBlock.filterPasses.length-1; i++) - { - var filterPass = filterBlock.filterPasses[i]; - - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); - - // draw texture.. - //filterPass.applyFilterPass(filterArea.width, filterArea.height); - this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); - - // swap the textures.. - var temp = inputTexture; - inputTexture = outputTexture; - outputTexture = temp; - - }; - - gl.enable(gl.BLEND); - - texture = inputTexture; - this.texturePool.push(outputTexture); - } - - var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; - - this.offsetX -= filterArea.x; - this.offsetY -= filterArea.y; - - - var sizeX = this.width; - var sizeY = this.height; - - var offsetX = 0; - var offsetY = 0; - - var buffer = this.buffer; - - // time to render the filters texture to the previous scene - if(this.filterStack.length === 0) - { - gl.colorMask(true, true, true, this.transparent); - } - else - { - var currentFilter = this.filterStack[this.filterStack.length-1]; - var filterArea = currentFilter.target.filterArea; - - sizeX = filterArea.width; - sizeY = filterArea.height; - - offsetX = filterArea.x; - offsetY = filterArea.y; - - buffer = currentFilter._glFilterTexture.frameBuffer; - } - - - - // TODO need toremove thease global elements.. - PIXI.projection.x = sizeX/2; - PIXI.projection.y = -sizeY/2; - - PIXI.offset.x = offsetX; - PIXI.offset.y = offsetY; - - - var filterArea = filterBlock.target.filterArea; - var x = filterArea.x-offsetX; - var y = filterArea.y-offsetY; - - // update the buffers.. - // make sure to flip the y! - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = x; - this.vertexArray[1] = y + filterArea.height; - - this.vertexArray[2] = x + filterArea.width; - this.vertexArray[3] = y + filterArea.height; - - this.vertexArray[4] = x; - this.vertexArray[5] = y; - - this.vertexArray[6] = x + filterArea.width; - this.vertexArray[7] = y; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - gl.viewport(0, 0, sizeX, sizeY); - // bind the buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - // apply! - //filter.applyFilterPass(sizeX, sizeY); - this.applyFilterPass(filter, filterArea, sizeX, sizeY); - - // now restore the regular shader.. - gl.useProgram(PIXI.defaultShader.program); - gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); - - // return the texture to the pool - this.texturePool.push(texture); - filterBlock._glFilterTexture = null; -} - -PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) -{ - // use program - var gl = PIXI.gl; - - if(!filter.shader) - { - var shader = new PIXI.PixiShader(); - - shader.fragmentSrc = filter.fragmentSrc; - shader.uniforms = filter.uniforms; - shader.init(); - - filter.shader = shader; - } - - var shader = filter.shader; - - // set the shader - gl.useProgram(shader.program); - - gl.uniform2f(shader.projectionVector, width/2, -height/2); - gl.uniform2f(shader.offsetVector, 0,0) - - if(filter.uniforms.dimensions) - { - //console.log(filter.uniforms.dimensions) - filter.uniforms.dimensions.value[0] = this.width;//width; - filter.uniforms.dimensions.value[1] = this.height;//height; - filter.uniforms.dimensions.value[2] = this.vertexArray[0]; - filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; - // console.log(this.vertexArray[5]) - } - - shader.syncUniforms(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // draw the filter... - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); -} - -PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() -{ - var gl = PIXI.gl; - - // create some buffers - this.vertexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // bind and upload the vertexs.. - // keep a refferance to the vertexFloatData.. - this.vertexArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.vertexArray, - gl.STATIC_DRAW); - - - // bind and upload the uv buffer - this.uvArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.uvArray, - gl.STATIC_DRAW); - - // bind and upload the index - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData( - gl.ELEMENT_ARRAY_BUFFER, - new Uint16Array([0, 1, 2, 1, 3, 2]), - gl.STATIC_DRAW); -} - -PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) -{ - // time to get the width and height of the object! - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; - var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - - var maxX = -Infinity; - var maxY = -Infinity; - - var minX = Infinity; - var minY = Infinity; - - do - { - // TODO can be optimized! - what if there is no scale / rotation? - - if(tempObject.visible) - { - if(tempObject instanceof PIXI.Sprite) - { - width = tempObject.texture.frame.width; - height = tempObject.texture.frame.height; - - // TODO trim?? - aX = tempObject.anchor.x; - aY = tempObject.anchor.y; - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - doTest = true; - } - else if(tempObject instanceof PIXI.Graphics) - { - tempObject.updateFilterBounds(); - - var bounds = tempObject.bounds; - - width = bounds.width; - height = bounds.height; - - w0 = bounds.x - w1 = bounds.x + bounds.width; - - h0 = bounds.y - h1 = bounds.y + bounds.height; - - doTest = true; - } - } - - if(doTest) - { - worldTransform = tempObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - x1 = a * w1 + c * h1 + tx; - y1 = d * h1 + b * w1 + ty; - - x2 = a * w0 + c * h1 + tx; - y2 = d * h1 + b * w0 + ty; - - x3 = a * w0 + c * h0 + tx; - y3 = d * h0 + b * w0 + ty; - - x4 = a * w1 + c * h0 + tx; - y4 = d * h0 + b * w1 + ty; - - minX = x1 < minX ? x1 : minX; - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y1 < minY ? y1 : minY; - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x1 > maxX ? x1 : maxX; - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1 > maxY ? y1 : maxY; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - } - - doTest = false; - tempObject = tempObject._iNext; - - } - while(tempObject != testObject) - - // maximum bounds is the size of the screen.. - //minX = minX > 0 ? minX : 0; - //minY = minY > 0 ? minY : 0; - - displayObject.filterArea.x = minX; - displayObject.filterArea.y = minY; - -// console.log(maxX+ " : " + minX) - displayObject.filterArea.width = maxX - minX; - displayObject.filterArea.height = maxY - minY; -} - -PIXI.FilterTexture = function(width, height) -{ - var gl = PIXI.gl; - - // next time to create a frame buffer and texture - this.frameBuffer = gl.createFramebuffer(); - this.texture = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - this.resize(width, height); -} - -PIXI.FilterTexture.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - var gl = PIXI.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class CanvasRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - */ -PIXI.CanvasRenderer = function(width, height, view, transparent) -{ - this.transparent = transparent; - - /** - * The width of the canvas view - * - * @property width - * @type Number - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @property height - * @type Number - * @default 600 - */ - this.height = height || 600; - - /** - * The canvas element that the everything is drawn to - * - * @property view - * @type Canvas - */ - this.view = view || document.createElement( 'canvas' ); - - /** - * The canvas context that the everything is drawn to - * @property context - * @type Canvas 2d Context - */ - this.context = this.view.getContext("2d"); - - this.refresh = true; - // hack to enable some hardware acceleration! - //this.view.style["transform"] = "translatez(0)"; - - this.view.width = this.width; - this.view.height = this.height; - this.count = 0; -} - -// constructor -PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; - -/** - * Renders the stage to its canvas view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.CanvasRenderer.prototype.render = function(stage) -{ - - //stage.__childrenAdded = []; - //stage.__childrenRemoved = []; - - // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - - PIXI.visibleCount++; - stage.updateTransform(); - - // update the background color - if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; - - this.context.setTransform(1,0,0,1,0,0); - this.context.clearRect(0, 0, this.width, this.height) - this.renderDisplayObject(stage); - //as - - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // remove frame updates.. - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates = []; - } - - -} - -/** - * resizes the canvas view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the canvas view - * @param height {Number} the new height of the canvas view - */ -PIXI.CanvasRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; -} - -/** - * Renders a display object - * - * @method renderDisplayObject - * @param displayObject {DisplayObject} The displayObject to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) -{ - // no loger recurrsive! - var transform; - var context = this.context; - - context.globalCompositeOperation = 'source-over'; - - // one the display object hits this. we can break the loop - var testObject = displayObject.last._iNext; - displayObject = displayObject.first; - - do - { - transform = displayObject.worldTransform; - - if(!displayObject.visible) - { - displayObject = displayObject.last._iNext; - continue; - } - - if(!displayObject.renderable) - { - displayObject = displayObject._iNext; - continue; - } - - if(displayObject instanceof PIXI.Sprite) - { - - var frame = displayObject.texture.frame; - - if(frame && frame.width && frame.height) - { - context.globalAlpha = displayObject.worldAlpha; - - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - - context.drawImage(displayObject.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - (displayObject.anchor.x) * -frame.width, - (displayObject.anchor.y) * -frame.height, - frame.width, - frame.height); - } - } - else if(displayObject instanceof PIXI.Strip) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderStrip(displayObject); - } - else if(displayObject instanceof PIXI.TilingSprite) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderTilingSprite(displayObject); - } - else if(displayObject instanceof PIXI.CustomRenderable) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - displayObject.renderCanvas(this); - } - else if(displayObject instanceof PIXI.Graphics) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - PIXI.CanvasGraphics.renderGraphics(displayObject, context); - } - else if(displayObject instanceof PIXI.FilterBlock) - { - if(displayObject.data instanceof PIXI.Graphics) - { - var mask = displayObject.data; - - if(displayObject.open) - { - context.save(); - - var cacheAlpha = mask.alpha; - var maskTransform = mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(mask, context); - context.clip(); - - mask.worldAlpha = cacheAlpha; - } - else - { - context.restore(); - } - } - else - { - // only masks supported right now! - } - } - // count++ - displayObject = displayObject._iNext; - - - } - while(displayObject != testObject) - - -} - -/** - * Renders a flat strip - * - * @method renderStripFlat - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) -{ - var context = this.context; - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - - context.beginPath(); - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - }; - - context.fillStyle = "#FF0000"; - context.fill(); - context.closePath(); -} - -/** - * Renders a tiling sprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tilingsprite to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) -{ - var context = this.context; - - context.globalAlpha = sprite.worldAlpha; - - if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); - - context.beginPath(); - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - // offset - context.scale(tileScale.x,tileScale.y); - context.translate(tilePosition.x, tilePosition.y); - - context.fillStyle = sprite.__tilePattern; - context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); - - context.scale(1/tileScale.x, 1/tileScale.y); - context.translate(-tilePosition.x, -tilePosition.y); - - context.closePath(); -} - -/** - * Renders a strip - * - * @method renderStrip - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStrip = function(strip) -{ - var context = this.context; - - // draw triangles!! - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; - var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; - - - context.save(); - context.beginPath(); - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - context.closePath(); - - context.clip(); - - - // Compute matrix transform - var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; - var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; - var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; - var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; - var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; - var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; - var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; - - - - - context.transform(delta_a/delta, delta_d/delta, - delta_b/delta, delta_e/delta, - delta_c/delta, delta_f/delta); - - context.drawImage(strip.texture.baseTexture.source, 0, 0); - context.restore(); - }; - -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A set of functions used by the canvas renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.CanvasGraphics = function() -{ - -} - - -/* - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphics = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); - - context.lineWidth = data.lineWidth; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - - if(data.fillColor || data.fillColor === 0) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); - - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); - } - - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - - }; -} - -/* - * Renders a graphics mask - * - * @static - * @private - * @method renderGraphicsMask - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - var len = graphics.graphicsData.length; - if(len === 0)return; - - if(len > 1) - { - len = 1; - console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") - } - - for (var i=0; i < 1; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - } - else if(data.type == PIXI.Graphics.RECT) - { - context.beginPath(); - context.rect(points[0], points[1], points[2], points[3]); - context.closePath(); - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - } - - - }; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. - * It is important to know that with the webGL renderer only simple polys can be filled at this stage - * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png - * - * @class Graphics - * @extends DisplayObjectContainer - * @constructor - */ -PIXI.Graphics = function() -{ - PIXI.DisplayObjectContainer.call( this ); - - this.renderable = true; - - /** - * The alpha of the fill of this graphics object - * - * @property fillAlpha - * @type Number - */ - this.fillAlpha = 1; - - /** - * The width of any lines drawn - * - * @property lineWidth - * @type Number - */ - this.lineWidth = 0; - - /** - * The color of any lines drawn - * - * @property lineColor - * @type String - */ - this.lineColor = "black"; - - /** - * Graphics data - * - * @property graphicsData - * @type Array - * @private - */ - this.graphicsData = []; - - /** - * Current path - * - * @property currentPath - * @type Object - * @private - */ - this.currentPath = {points:[]}; -} - -// constructor -PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Graphics.prototype.constructor = PIXI.Graphics; - -/** - * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. - * - * @method lineStyle - * @param lineWidth {Number} width of the line to draw, will update the object's stored style - * @param color {Number} color of the line to draw, will update the object's stored style - * @param alpha {Number} alpha of the line to draw, will update the object's stored style - */ -PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.lineWidth = lineWidth || 0; - this.lineColor = color || 0; - this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); -} - -/** - * Moves the current drawing position to (x, y). - * - * @method moveTo - * @param x {Number} the X coord to move to - * @param y {Number} the Y coord to move to - */ -PIXI.Graphics.prototype.moveTo = function(x, y) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.currentPath.points.push(x, y); - - this.graphicsData.push(this.currentPath); -} - -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coord to draw to - * @param y {Number} the Y coord to draw to - */ -PIXI.Graphics.prototype.lineTo = function(x, y) -{ - this.currentPath.points.push(x, y); - this.dirty = true; -} - -/** - * Specifies a simple one-color fill that subsequent calls to other Graphics methods - * (such as lineTo() or drawCircle()) use when drawing. - * - * @method beginFill - * @param color {uint} the color of the fill - * @param alpha {Number} the alpha - */ -PIXI.Graphics.prototype.beginFill = function(color, alpha) -{ - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha == undefined) ? 1 : alpha; -} - -/** - * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. - * - * @method endFill - */ -PIXI.Graphics.prototype.endFill = function() -{ - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; -} - -/** - * @method drawRect - * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle - */ -PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws a circle. - * - * @method drawCircle - * @param x {Number} The X coord of the center of the circle - * @param y {Number} The Y coord of the center of the circle - * @param radius {Number} The radius of the circle - */ -PIXI.Graphics.prototype.drawCircle = function( x, y, radius) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws an elipse. - * - * @method drawElipse - * @param x {Number} - * @param y {Number} - * @param width {Number} - * @param height {Number} - */ -PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. - * - * @method clear - */ -PIXI.Graphics.prototype.clear = function() -{ - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; - - this.bounds = null//new PIXI.Rectangle(); -} - - -PIXI.Graphics.prototype.updateFilterBounds = function() -{ - if(!this.bounds) - { - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - var points, x, y; - - for (var i = 0; i < this.graphicsData.length; i++) { - - - var data = this.graphicsData[i]; - var type = data.type; - var lineWidth = data.lineWidth; - - points = data.points; - - if(type === PIXI.Graphics.RECT) - { - x = points.x - lineWidth/2; - y = points.y - lineWidth/2; - var width = points.width + lineWidth; - var height = points.height + lineWidth; - - minX = x < minX ? x : minX; - maxX = x + width > maxX ? x + width : maxX; - - minY = y < minY ? x : minY; - maxY = y + height > maxY ? y + height : maxY; - } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) - { - x = points.x; - y = points.y; - var radius = points.radius + lineWidth/2; - - minX = x - radius < minX ? x - radius : minX; - maxX = x + radius > maxX ? x + radius : maxX; - - minY = y - radius < minY ? y - radius : minY; - maxY = y + radius > maxY ? y + radius : maxY; - } - else - { - // POLY - for (var j = 0; j < points.length; j+=2) - { - - x = points[j]; - y = points[j+1]; - - minX = x-lineWidth < minX ? x-lineWidth : minX; - maxX = x+lineWidth > maxX ? x+lineWidth : maxX; - - minY = y-lineWidth < minY ? y-lineWidth : minY; - maxY = y+lineWidth > maxY ? y+lineWidth : maxY; - }; - } - - }; - - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); - - } - -// console.log(this.bounds); -} - -// SOME TYPES: -PIXI.Graphics.POLY = 0; -PIXI.Graphics.RECT = 1; -PIXI.Graphics.CIRC = 2; -PIXI.Graphics.ELIP = 3; - -/** - * @author Mat Groves http://matgroves.com/ - */ - -PIXI.Strip = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - this.texture = texture; - this.blendMode = PIXI.blendModes.NORMAL; - - try - { - this.uvs = new Float32Array([0, 1, - 1, 1, - 1, 0, 0,1]); - - this.verticies = new Float32Array([0, 0, - 0,0, - 0,0, 0, - 0, 0]); - - this.colors = new Float32Array([1, 1, 1, 1]); - - this.indices = new Uint16Array([0, 1, 2, 3]); - } - catch(error) - { - this.uvs = [0, 1, - 1, 1, - 1, 0, 0,1]; - - this.verticies = [0, 0, - 0,0, - 0,0, 0, - 0, 0]; - - this.colors = [1, 1, 1, 1]; - - this.indices = [0, 1, 2, 3]; - } - - - /* - this.uvs = new Float32Array() - this.verticies = new Float32Array() - this.colors = new Float32Array() - this.indices = new Uint16Array() -*/ - this.width = width; - this.height = height; - - // load the texture! - if(texture.baseTexture.hasLoaded) - { - this.width = this.texture.frame.width; - this.height = this.texture.frame.height; - this.updateFrame = true; - } - else - { - this.onTextureUpdateBind = this.onTextureUpdate.bind(this); - this.texture.addEventListener( 'update', this.onTextureUpdateBind ); - } - - this.renderable = true; -} - -// constructor -PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Strip.prototype.constructor = PIXI.Strip; - -PIXI.Strip.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.width = texture.frame.width; - this.height = texture.frame.height; - this.updateFrame = true; -} - -PIXI.Strip.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} -// some helper functions.. - - -/** - * @author Mat Groves http://matgroves.com/ - */ - - -PIXI.Rope = function(texture, points) -{ - PIXI.Strip.call( this, texture ); - this.points = points; - - try - { - this.verticies = 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); - } - catch(error) - { - this.verticies = verticies - - this.uvs = uvs - this.colors = colors - this.indices = indices - } - - this.refresh(); -} - - -// constructor -PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); -PIXI.Rope.prototype.constructor = PIXI.Rope; - -PIXI.Rope.prototype.refresh = function() -{ - var points = this.points; - if(points.length < 1)return; - - var uvs = this.uvs - var indices = this.indices; - var colors = this.colors; - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - - uvs[0] = 0 - uvs[1] = 1 - uvs[2] = 0 - uvs[3] = 1 - - colors[0] = 1; - colors[1] = 1; - - indices[0] = 0; - indices[1] = 1; - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - // time to do some smart drawing! - var amount = i/(total-1) - - if(i%2) - { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount - uvs[index+3] = 1 - - } - else - { - uvs[index] = amount - uvs[index+1] = 0 - - uvs[index+2] = amount - uvs[index+3] = 1 - } - - index = i * 2; - colors[index] = 1; - colors[index+1] = 1; - - index = i * 2; - indices[index] = index; - indices[index + 1] = index + 1; - - lastPoint = point; - } -} - -PIXI.Rope.prototype.updateTransform = function() -{ - - var points = this.points; - if(points.length < 1)return; - - var verticies = this.verticies - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - verticies[0] = point.x + perp.x - verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x - verticies[3] = point.y - perp.y//+200 - // time to do some smart drawing! - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - - if(i < points.length-1) - { - nextPoint = points[i+1]; - } - else - { - nextPoint = point - } - - perp.y = -(nextPoint.x - lastPoint.x); - perp.x = nextPoint.y - lastPoint.y; - - var ratio = (1 - (i / (total-1))) * 10; - if(ratio > 1)ratio = 1; - - var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); - var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; - perp.x /= perpLength; - perp.y /= perpLength; - - perp.x *= num; - perp.y *= num; - - verticies[index] = point.x + perp.x - verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x - verticies[index+3] = point.y - perp.y - - lastPoint = point; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); -} - -PIXI.Rope.prototype.setTexture = function(texture) -{ - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * A tiling sprite is a fast way of rendering a tiling image - * - * @class TilingSprite - * @extends DisplayObjectContainer - * @constructor - * @param texture {Texture} the texture of the tiling sprite - * @param width {Number} the width of the tiling sprite - * @param height {Number} the height of the tiling sprite - */ -PIXI.TilingSprite = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * The texture that the sprite is using - * - * @property texture - * @type Texture - */ - this.texture = texture; - - /** - * The width of the tiling sprite - * - * @property width - * @type Number - */ - this.width = width; - - /** - * The height of the tiling sprite - * - * @property height - * @type Number - */ - this.height = height; - - /** - * The scaling of the image that is being tiled - * - * @property tileScale - * @type Point - */ - this.tileScale = new PIXI.Point(1,1); - - /** - * The offset position of the image that is being tiled - * - * @property tilePosition - * @type Point - */ - this.tilePosition = new PIXI.Point(0,0); - - this.renderable = true; - - this.blendMode = PIXI.blendModes.NORMAL -} - -// constructor -PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; - -/** - * Sets the texture of the tiling sprite - * - * @method setTexture - * @param texture {Texture} The PIXI texture that is displayed by the sprite - */ -PIXI.TilingSprite.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - -/** - * When the texture is updated, this event will fire to update the frame - * - * @method onTextureUpdate - * @param event - * @private - */ -PIXI.TilingSprite.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * - * Awesome JS run time provided by EsotericSoftware - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -/** - * A class that enables the you to import and run your spine animations in pixi. - * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * - * @class Spine - * @extends DisplayObjectContainer - * @constructor - * @param url {String} The url of the spine anim file to be used - */ -PIXI.Spine = function (url) { - PIXI.DisplayObjectContainer.call(this); - - this.spineData = PIXI.AnimCache[url]; - - if (!this.spineData) { - throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - } - - this.skeleton = new spine.Skeleton(this.spineData); - this.skeleton.updateWorldTransform(); - - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); - - this.slotContainers = []; - - for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { - var slot = this.skeleton.drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = new PIXI.DisplayObjectContainer(); - this.slotContainers.push(slotContainer); - this.addChild(slotContainer); - if (!(attachment instanceof spine.RegionAttachment)) { - continue; - } - var spriteName = attachment.rendererObject.name; - var sprite = this.createSprite(slot, attachment.rendererObject); - slot.currentSprite = sprite; - slot.currentSpriteName = spriteName; - slotContainer.addChild(sprite); - } -}; - -PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.Spine.prototype.constructor = PIXI.Spine; - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Spine.prototype.updateTransform = function () { - this.lastTime = this.lastTime || Date.now(); - var timeDelta = (Date.now() - this.lastTime) * 0.001; - this.lastTime = Date.now(); - this.state.update(timeDelta); - this.state.apply(this.skeleton); - this.skeleton.updateWorldTransform(); - - var drawOrder = this.skeleton.drawOrder; - for (var i = 0, n = drawOrder.length; i < n; i++) { - var slot = drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = this.slotContainers[i]; - if (!(attachment instanceof spine.RegionAttachment)) { - slotContainer.visible = false; - continue; - } - - if (attachment.rendererObject) { - if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { - var spriteName = attachment.rendererObject.name; - if (slot.currentSprite !== undefined) { - slot.currentSprite.visible = false; - } - slot.sprites = slot.sprites || {}; - if (slot.sprites[spriteName] !== undefined) { - slot.sprites[spriteName].visible = true; - } else { - var sprite = this.createSprite(slot, attachment.rendererObject); - slotContainer.addChild(sprite); - } - slot.currentSprite = slot.sprites[spriteName]; - slot.currentSpriteName = spriteName; - } - } - slotContainer.visible = true; - - var bone = slot.bone; - - slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; - slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; - slotContainer.scale.x = bone.worldScaleX; - slotContainer.scale.y = bone.worldScaleY; - - slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - - -PIXI.Spine.prototype.createSprite = function (slot, descriptor) { - var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); - sprite.scale = descriptor.scale; - sprite.rotation = descriptor.rotation; - sprite.anchor.x = sprite.anchor.y = 0.5; - - slot.sprites = slot.sprites || {}; - slot.sprites[descriptor.name] = sprite; - return sprite; -}; - -/* - * Awesome JS run time provided by EsotericSoftware - * - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -var spine = {}; - -spine.BoneData = function (name, parent) { - this.name = name; - this.parent = parent; -}; -spine.BoneData.prototype = { - length: 0, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1 -}; - -spine.SlotData = function (name, boneData) { - this.name = name; - this.boneData = boneData; -}; -spine.SlotData.prototype = { - r: 1, g: 1, b: 1, a: 1, - attachmentName: null -}; - -spine.Bone = function (boneData, parent) { - this.data = boneData; - this.parent = parent; - this.setToSetupPose(); -}; -spine.Bone.yDown = false; -spine.Bone.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - m00: 0, m01: 0, worldX: 0, // a b x - m10: 0, m11: 0, worldY: 0, // c d y - worldRotation: 0, - worldScaleX: 1, worldScaleY: 1, - updateWorldTransform: function (flipX, flipY) { - var parent = this.parent; - if (parent != null) { - this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; - this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; - this.worldScaleX = parent.worldScaleX * this.scaleX; - this.worldScaleY = parent.worldScaleY * this.scaleY; - this.worldRotation = parent.worldRotation + this.rotation; - } else { - this.worldX = this.x; - this.worldY = this.y; - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - this.worldRotation = this.rotation; - } - var radians = this.worldRotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - this.m00 = cos * this.worldScaleX; - this.m10 = sin * this.worldScaleX; - this.m01 = -sin * this.worldScaleY; - this.m11 = cos * this.worldScaleY; - if (flipX) { - this.m00 = -this.m00; - this.m01 = -this.m01; - } - if (flipY) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - if (spine.Bone.yDown) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - }, - setToSetupPose: function () { - var data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - } -}; - -spine.Slot = function (slotData, skeleton, bone) { - this.data = slotData; - this.skeleton = skeleton; - this.bone = bone; - this.setToSetupPose(); -}; -spine.Slot.prototype = { - r: 1, g: 1, b: 1, a: 1, - _attachmentTime: 0, - attachment: null, - setAttachment: function (attachment) { - this.attachment = attachment; - this._attachmentTime = this.skeleton.time; - }, - setAttachmentTime: function (time) { - this._attachmentTime = this.skeleton.time - time; - }, - getAttachmentTime: function () { - return this.skeleton.time - this._attachmentTime; - }, - setToSetupPose: function () { - var data = this.data; - this.r = data.r; - this.g = data.g; - this.b = data.b; - this.a = data.a; - - var slotDatas = this.skeleton.data.slots; - for (var i = 0, n = slotDatas.length; i < n; i++) { - if (slotDatas[i] == data) { - this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); - break; - } - } - } -}; - -spine.Skin = function (name) { - this.name = name; - this.attachments = {}; -}; -spine.Skin.prototype = { - addAttachment: function (slotIndex, name, attachment) { - this.attachments[slotIndex + ":" + name] = attachment; - }, - getAttachment: function (slotIndex, name) { - return this.attachments[slotIndex + ":" + name]; - }, - _attachAll: function (skeleton, oldSkin) { - for (var key in oldSkin.attachments) { - var colon = key.indexOf(":"); - var slotIndex = parseInt(key.substring(0, colon)); - var name = key.substring(colon + 1); - var slot = skeleton.slots[slotIndex]; - if (slot.attachment && slot.attachment.name == name) { - var attachment = this.getAttachment(slotIndex, name); - if (attachment) slot.setAttachment(attachment); - } - } - } -}; - -spine.Animation = function (name, timelines, duration) { - this.name = name; - this.timelines = timelines; - this.duration = duration; -}; -spine.Animation.prototype = { - apply: function (skeleton, time, loop) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, 1); - }, - mix: function (skeleton, time, loop, alpha) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, alpha); - } -}; - -spine.binarySearch = function (values, target, step) { - var low = 0; - var high = Math.floor(values.length / step) - 2; - if (high == 0) return step; - var current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } -}; -spine.linearSearch = function (values, target, step) { - for (var i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; -}; - -spine.Curves = function (frameCount) { - this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... - this.curves.length = (frameCount - 1) * 6; -}; -spine.Curves.prototype = { - setLinear: function (frameIndex) { - this.curves[frameIndex * 6] = 0/*LINEAR*/; - }, - setStepped: function (frameIndex) { - this.curves[frameIndex * 6] = -1/*STEPPED*/; - }, - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { - var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; - var subdiv_step2 = subdiv_step * subdiv_step; - var subdiv_step3 = subdiv_step2 * subdiv_step; - var pre1 = 3 * subdiv_step; - var pre2 = 3 * subdiv_step2; - var pre4 = 6 * subdiv_step2; - var pre5 = 6 * subdiv_step3; - var tmp1x = -cx1 * 2 + cx2; - var tmp1y = -cy1 * 2 + cy2; - var tmp2x = (cx1 - cx2) * 3 + 1; - var tmp2y = (cy1 - cy2) * 3 + 1; - var i = frameIndex * 6; - var curves = this.curves; - curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; - curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; - curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; - curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; - curves[i + 4] = tmp2x * pre5; - curves[i + 5] = tmp2y * pre5; - }, - getCurvePercent: function (frameIndex, percent) { - percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); - var curveIndex = frameIndex * 6; - var curves = this.curves; - var dfx = curves[curveIndex]; - if (!dfx/*LINEAR*/) return percent; - if (dfx == -1/*STEPPED*/) return 0; - var dfy = curves[curveIndex + 1]; - var ddfx = curves[curveIndex + 2]; - var ddfy = curves[curveIndex + 3]; - var dddfx = curves[curveIndex + 4]; - var dddfy = curves[curveIndex + 5]; - var x = dfx, y = dfy; - var i = 10/*BEZIER_SEGMENTS*/ - 2; - while (true) { - if (x >= percent) { - var lastX = x - dfx; - var lastY = y - dfy; - return lastY + (y - lastY) * (percent - lastX) / (x - lastX); - } - if (i == 0) break; - i--; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -}; - -spine.RotateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, angle, ... - this.frames.length = frameCount * 2; -}; -spine.RotateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, angle) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = angle; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 2]) { // Time is after last frame. - var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 2); - var lastFrameValue = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); - - var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -}; - -spine.TranslateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.TranslateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; - } -}; - -spine.ScaleTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.ScaleTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; - } -}; - -spine.ColorTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, r, g, b, a, ... - this.frames.length = frameCount * 5; -}; -spine.ColorTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 5; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = r; - this.frames[frameIndex + 2] = g; - this.frames[frameIndex + 3] = b; - this.frames[frameIndex + 4] = a; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var slot = skeleton.slots[this.slotIndex]; - - if (time >= frames[frames.length - 5]) { // Time is after last frame. - var i = frames.length - 1; - slot.r = frames[i - 3]; - slot.g = frames[i - 2]; - slot.b = frames[i - 1]; - slot.a = frames[i]; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 5); - var lastFrameR = frames[frameIndex - 4]; - var lastFrameG = frames[frameIndex - 3]; - var lastFrameB = frames[frameIndex - 2]; - var lastFrameA = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); - - var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; - var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; - var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; - var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -}; - -spine.AttachmentTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, ... - this.frames.length = frameCount; - this.attachmentNames = []; // time, ... - this.attachmentNames.length = frameCount; -}; -spine.AttachmentTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, attachmentName) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = spine.binarySearch(frames, time, 1) - 1; - - var attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); - } -}; - -spine.SkeletonData = function () { - this.bones = []; - this.slots = []; - this.skins = []; - this.animations = []; -}; -spine.SkeletonData.prototype = { - defaultSkin: null, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - if (slots[i].name == slotName) return slot[i]; - } - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - }, - /** @return May be null. */ - findSkin: function (skinName) { - var skins = this.skins; - for (var i = 0, n = skins.length; i < n; i++) - if (skins[i].name == skinName) return skins[i]; - return null; - }, - /** @return May be null. */ - findAnimation: function (animationName) { - var animations = this.animations; - for (var i = 0, n = animations.length; i < n; i++) - if (animations[i].name == animationName) return animations[i]; - return null; - } -}; - -spine.Skeleton = function (skeletonData) { - this.data = skeletonData; - - this.bones = []; - for (var i = 0, n = skeletonData.bones.length; i < n; i++) { - var boneData = skeletonData.bones[i]; - var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; - this.bones.push(new spine.Bone(boneData, parent)); - } - - this.slots = []; - this.drawOrder = []; - for (var i = 0, n = skeletonData.slots.length; i < n; i++) { - var slotData = skeletonData.slots[i]; - var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; - var slot = new spine.Slot(slotData, this, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } -}; -spine.Skeleton.prototype = { - x: 0, y: 0, - skin: null, - r: 1, g: 1, b: 1, a: 1, - time: 0, - flipX: false, flipY: false, - /** Updates the world transform for each bone. */ - updateWorldTransform: function () { - var flipX = this.flipX; - var flipY = this.flipY; - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].updateWorldTransform(flipX, flipY); - }, - /** Sets the bones and slots to their setup pose values. */ - setToSetupPose: function () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - }, - setBonesToSetupPose: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - }, - setSlotsToSetupPose: function () { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - slots[i].setToSetupPose(i); - }, - /** @return May return null. */ - getRootBone: function () { - return this.bones.length == 0 ? null : this.bones[0]; - }, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return slots[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - }, - setSkinByName: function (skinName) { - var skin = this.data.findSkin(skinName); - if (!skin) throw "Skin not found: " + skinName; - this.setSkin(skin); - }, - /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments - * from the new skin are attached if the corresponding attachment from the old skin was attached. - * @param newSkin May be null. */ - setSkin: function (newSkin) { - if (this.skin && newSkin) newSkin._attachAll(this, this.skin); - this.skin = newSkin; - }, - /** @return May be null. */ - getAttachmentBySlotName: function (slotName, attachmentName) { - return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); - }, - /** @return May be null. */ - getAttachmentBySlotIndex: function (slotIndex, attachmentName) { - if (this.skin) { - var attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment) return attachment; - } - if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - }, - /** @param attachmentName May be null. */ - setAttachment: function (slotName, attachmentName) { - var slots = this.slots; - for (var i = 0, n = slots.size; i < n; i++) { - var slot = slots[i]; - if (slot.data.name == slotName) { - var attachment = null; - if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); - if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; - } - slot.setAttachment(attachment); - return; - } - } - throw "Slot not found: " + slotName; - }, - update: function (delta) { - time += delta; - } -}; - -spine.AttachmentType = { - region: 0 -}; - -spine.RegionAttachment = function () { - this.offset = []; - this.offset.length = 8; - this.uvs = []; - this.uvs.length = 8; -}; -spine.RegionAttachment.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - width: 0, height: 0, - rendererObject: null, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - setUVs: function (u, v, u2, v2, rotate) { - var uvs = this.uvs; - if (rotate) { - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v2; - uvs[4/*X3*/] = u; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v; - uvs[0/*X1*/] = u2; - uvs[1/*Y1*/] = v2; - } else { - uvs[0/*X1*/] = u; - uvs[1/*Y1*/] = v2; - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v; - uvs[4/*X3*/] = u2; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v2; - } - }, - updateOffset: function () { - var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; - var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; - var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; - var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; - var localX2 = localX + this.regionWidth * regionScaleX; - var localY2 = localY + this.regionHeight * regionScaleY; - var radians = this.rotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var localXCos = localX * cos + this.x; - var localXSin = localX * sin; - var localYCos = localY * cos + this.y; - var localYSin = localY * sin; - var localX2Cos = localX2 * cos + this.x; - var localX2Sin = localX2 * sin; - var localY2Cos = localY2 * cos + this.y; - var localY2Sin = localY2 * sin; - var offset = this.offset; - offset[0/*X1*/] = localXCos - localYSin; - offset[1/*Y1*/] = localYCos + localXSin; - offset[2/*X2*/] = localXCos - localY2Sin; - offset[3/*Y2*/] = localY2Cos + localXSin; - offset[4/*X3*/] = localX2Cos - localY2Sin; - offset[5/*Y3*/] = localY2Cos + localX2Sin; - offset[6/*X4*/] = localX2Cos - localYSin; - offset[7/*Y4*/] = localYCos + localX2Sin; - }, - computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00; - var m01 = bone.m01; - var m10 = bone.m10; - var m11 = bone.m11; - var offset = this.offset; - vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; - vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; - vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; - vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; - vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; - vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; - vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; - vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; - } -} - -spine.AnimationStateData = function (skeletonData) { - this.skeletonData = skeletonData; - this.animationToMixTime = {}; -}; -spine.AnimationStateData.prototype = { - defaultMix: 0, - setMixByName: function (fromName, toName, duration) { - var from = this.skeletonData.findAnimation(fromName); - if (!from) throw "Animation not found: " + fromName; - var to = this.skeletonData.findAnimation(toName); - if (!to) throw "Animation not found: " + toName; - this.setMix(from, to, duration); - }, - setMix: function (from, to, duration) { - this.animationToMixTime[from.name + ":" + to.name] = duration; - }, - getMix: function (from, to) { - var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : this.defaultMix; - } -}; - -spine.AnimationState = function (stateData) { - this.data = stateData; - this.queue = []; -}; -spine.AnimationState.prototype = { - current: null, - previous: null, - currentTime: 0, - previousTime: 0, - currentLoop: false, - previousLoop: false, - mixTime: 0, - mixDuration: 0, - update: function (delta) { - this.currentTime += delta; - this.previousTime += delta; - this.mixTime += delta; - - if (this.queue.length > 0) { - var entry = this.queue[0]; - if (this.currentTime >= entry.delay) { - this._setAnimation(entry.animation, entry.loop); - this.queue.shift(); - } - } - }, - apply: function (skeleton) { - if (!this.current) return; - if (this.previous) { - this.previous.apply(skeleton, this.previousTime, this.previousLoop); - var alpha = this.mixTime / this.mixDuration; - if (alpha >= 1) { - alpha = 1; - this.previous = null; - } - this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else - this.current.apply(skeleton, this.currentTime, this.currentLoop); - }, - clearAnimation: function () { - this.previous = null; - this.current = null; - this.queue.length = 0; - }, - _setAnimation: function (animation, loop) { - this.previous = null; - if (animation && this.current) { - this.mixDuration = this.data.getMix(this.current, animation); - if (this.mixDuration > 0) { - this.mixTime = 0; - this.previous = this.current; - this.previousTime = this.currentTime; - this.previousLoop = this.currentLoop; - } - } - this.current = animation; - this.currentLoop = loop; - this.currentTime = 0; - }, - /** @see #setAnimation(Animation, Boolean) */ - setAnimationByName: function (animationName, loop) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.setAnimation(animation, loop); - }, - /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. - * @param animation May be null. */ - setAnimation: function (animation, loop) { - this.queue.length = 0; - this._setAnimation(animation, loop); - }, - /** @see #addAnimation(Animation, Boolean, Number) */ - addAnimationByName: function (animationName, loop, delay) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.addAnimation(animation, loop, delay); - }, - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimation: function (animation, loop, delay) { - var entry = {}; - entry.animation = animation; - entry.loop = loop; - - if (!delay || delay <= 0) { - var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; - if (previousAnimation != null) - delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); - else - delay = 0; - } - entry.delay = delay; - - this.queue.push(entry); - }, - /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ - isComplete: function () { - return !this.current || this.currentTime >= this.current.duration; - } -}; - -spine.SkeletonJson = function (attachmentLoader) { - this.attachmentLoader = attachmentLoader; -}; -spine.SkeletonJson.prototype = { - scale: 1, - readSkeletonData: function (root) { - var skeletonData = new spine.SkeletonData(); - - // Bones. - var bones = root["bones"]; - for (var i = 0, n = bones.length; i < n; i++) { - var boneMap = bones[i]; - var parent = null; - if (boneMap["parent"]) { - parent = skeletonData.findBone(boneMap["parent"]); - if (!parent) throw "Parent bone not found: " + boneMap["parent"]; - } - var boneData = new spine.BoneData(boneMap["name"], parent); - boneData.length = (boneMap["length"] || 0) * this.scale; - boneData.x = (boneMap["x"] || 0) * this.scale; - boneData.y = (boneMap["y"] || 0) * this.scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap["scaleX"] || 1; - boneData.scaleY = boneMap["scaleY"] || 1; - skeletonData.bones.push(boneData); - } - - // Slots. - var slots = root["slots"]; - for (var i = 0, n = slots.length; i < n; i++) { - var slotMap = slots[i]; - var boneData = skeletonData.findBone(slotMap["bone"]); - if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; - var slotData = new spine.SlotData(slotMap["name"], boneData); - - var color = slotMap["color"]; - if (color) { - slotData.r = spine.SkeletonJson.toColor(color, 0); - slotData.g = spine.SkeletonJson.toColor(color, 1); - slotData.b = spine.SkeletonJson.toColor(color, 2); - slotData.a = spine.SkeletonJson.toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - - skeletonData.slots.push(slotData); - } - - // Skins. - var skins = root["skins"]; - for (var skinName in skins) { - if (!skins.hasOwnProperty(skinName)) continue; - var skinMap = skins[skinName]; - var skin = new spine.Skin(skinName); - for (var slotName in skinMap) { - if (!skinMap.hasOwnProperty(slotName)) continue; - var slotIndex = skeletonData.findSlotIndex(slotName); - var slotEntry = skinMap[slotName]; - for (var attachmentName in slotEntry) { - if (!slotEntry.hasOwnProperty(attachmentName)) continue; - var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); - if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - - // Animations. - var animations = root["animations"]; - for (var animationName in animations) { - if (!animations.hasOwnProperty(animationName)) continue; - this.readAnimation(animationName, animations[animationName], skeletonData); - } - - return skeletonData; - }, - readAttachment: function (skin, name, map) { - name = map["name"] || name; - - var type = spine.AttachmentType[map["type"] || "region"]; - - if (type == spine.AttachmentType.region) { - var attachment = new spine.RegionAttachment(); - attachment.x = (map["x"] || 0) * this.scale; - attachment.y = (map["y"] || 0) * this.scale; - attachment.scaleX = map["scaleX"] || 1; - attachment.scaleY = map["scaleY"] || 1; - attachment.rotation = map["rotation"] || 0; - attachment.width = (map["width"] || 32) * this.scale; - attachment.height = (map["height"] || 32) * this.scale; - attachment.updateOffset(); - - attachment.rendererObject = {}; - attachment.rendererObject.name = name; - attachment.rendererObject.scale = {}; - attachment.rendererObject.scale.x = attachment.scaleX; - attachment.rendererObject.scale.y = attachment.scaleY; - attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; - return attachment; - } - - throw "Unknown attachment type: " + type; - }, - - readAnimation: function (name, map, skeletonData) { - var timelines = []; - var duration = 0; - - var bones = map["bones"]; - for (var boneName in bones) { - if (!bones.hasOwnProperty(boneName)) continue; - var boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw "Bone not found: " + boneName; - var boneMap = bones[boneName]; - - for (var timelineName in boneMap) { - if (!boneMap.hasOwnProperty(timelineName)) continue; - var values = boneMap[timelineName]; - if (timelineName == "rotate") { - var timeline = new spine.RotateTimeline(values.length); - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - - } else if (timelineName == "translate" || timelineName == "scale") { - var timeline; - var timelineScale = 1; - if (timelineName == "scale") - timeline = new spine.ScaleTimeline(values.length); - else { - timeline = new spine.TranslateTimeline(values.length); - timelineScale = this.scale; - } - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var x = (valueMap["x"] || 0) * timelineScale; - var y = (valueMap["y"] || 0) * timelineScale; - timeline.setFrame(frameIndex, valueMap["time"], x, y); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - - } else - throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; - } - } - var slots = map["slots"]; - for (var slotName in slots) { - if (!slots.hasOwnProperty(slotName)) continue; - var slotMap = slots[slotName]; - var slotIndex = skeletonData.findSlotIndex(slotName); - - for (var timelineName in slotMap) { - if (!slotMap.hasOwnProperty(timelineName)) continue; - var values = slotMap[timelineName]; - if (timelineName == "color") { - var timeline = new spine.ColorTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var color = valueMap["color"]; - var r = spine.SkeletonJson.toColor(color, 0); - var g = spine.SkeletonJson.toColor(color, 1); - var b = spine.SkeletonJson.toColor(color, 2); - var a = spine.SkeletonJson.toColor(color, 3); - timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); - - } else if (timelineName == "attachment") { - var timeline = new spine.AttachmentTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - - } else - throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; - } - } - skeletonData.animations.push(new spine.Animation(name, timelines, duration)); - } -}; -spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { - var curve = valueMap["curve"]; - if (!curve) return; - if (curve == "stepped") - timeline.curves.setStepped(frameIndex); - else if (curve instanceof Array) - timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); -}; -spine.SkeletonJson.toColor = function (hexString, colorIndex) { - if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; - return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; -}; - -spine.Atlas = function (atlasText, textureLoader) { - this.textureLoader = textureLoader; - this.pages = []; - this.regions = []; - - var reader = new spine.AtlasReader(atlasText); - var tuple = []; - tuple.length = 4; - var page = null; - while (true) { - var line = reader.readLine(); - if (line == null) break; - line = reader.trim(line); - if (line.length == 0) - page = null; - else if (!page) { - page = new spine.AtlasPage(); - page.name = line; - - page.format = spine.Atlas.Format[reader.readValue()]; - - reader.readTuple(tuple); - page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; - page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; - - var direction = reader.readValue(); - page.uWrap = spine.Atlas.TextureWrap.clampToEdge; - page.vWrap = spine.Atlas.TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "y") - page.vWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; - - textureLoader.load(page, line); - - this.pages.push(page); - - } else { - var region = new spine.AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x = parseInt(tuple[0]); - var y = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width = parseInt(tuple[0]); - var height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - this.regions.push(region); - } - } -}; -spine.Atlas.prototype = { - findRegion: function (name) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - }, - dispose: function () { - var pages = this.pages; - for (var i = 0, n = pages.length; i < n; i++) - this.textureLoader.unload(pages[i].rendererObject); - }, - updateUVs: function (page) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) { - var region = regions[i]; - if (region.page != page) continue; - region.u = region.x / page.width; - region.v = region.y / page.height; - if (region.rotate) { - region.u2 = (region.x + region.height) / page.width; - region.v2 = (region.y + region.width) / page.height; - } else { - region.u2 = (region.x + region.width) / page.width; - region.v2 = (region.y + region.height) / page.height; - } - } - } -}; - -spine.Atlas.Format = { - alpha: 0, - intensity: 1, - luminanceAlpha: 2, - rgb565: 3, - rgba4444: 4, - rgb888: 5, - rgba8888: 6 -}; - -spine.Atlas.TextureFilter = { - nearest: 0, - linear: 1, - mipMap: 2, - mipMapNearestNearest: 3, - mipMapLinearNearest: 4, - mipMapNearestLinear: 5, - mipMapLinearLinear: 6 -}; - -spine.Atlas.TextureWrap = { - mirroredRepeat: 0, - clampToEdge: 1, - repeat: 2 -}; - -spine.AtlasPage = function () {}; -spine.AtlasPage.prototype = { - name: null, - format: null, - minFilter: null, - magFilter: null, - uWrap: null, - vWrap: null, - rendererObject: null, - width: 0, - height: 0 -}; - -spine.AtlasRegion = function () {}; -spine.AtlasRegion.prototype = { - page: null, - name: null, - x: 0, y: 0, - width: 0, height: 0, - u: 0, v: 0, u2: 0, v2: 0, - offsetX: 0, offsetY: 0, - originalWidth: 0, originalHeight: 0, - index: 0, - rotate: false, - splits: null, - pads: null, -}; - -spine.AtlasReader = function (text) { - this.lines = text.split(/\r\n|\r|\n/); -}; -spine.AtlasReader.prototype = { - index: 0, - trim: function (value) { - return value.replace(/^\s+|\s+$/g, ""); - }, - readLine: function () { - if (this.index >= this.lines.length) return null; - return this.lines[this.index++]; - }, - readValue: function () { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - return this.trim(line.substring(colon + 1)); - }, - /** Returns the number of tuple values read (2 or 4). */ - readTuple: function (tuple) { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - var i = 0, lastMatch= colon + 1; - for (; i < 3; i++) { - var comma = line.indexOf(",", lastMatch); - if (comma == -1) { - if (i == 0) throw "Invalid line: " + line; - break; - } - tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = this.trim(line.substring(lastMatch)); - return i + 1; - } -} - -spine.AtlasAttachmentLoader = function (atlas) { - this.atlas = atlas; -} -spine.AtlasAttachmentLoader.prototype = { - newAttachment: function (skin, type, name) { - switch (type) { - case spine.AttachmentType.region: - var region = this.atlas.findRegion(name); - if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; - var attachment = new spine.RegionAttachment(name); - attachment.rendererObject = region; - attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - throw "Unknown attachment type: " + type; - } -} - -PIXI.AnimCache = {}; -spine.Bone.yDown = true; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * This object is one that will allow you to specify custom rendering functions based on render type - * - * @class CustomRenderable - * @extends DisplayObject - * @constructor - */ -PIXI.CustomRenderable = function() -{ - PIXI.DisplayObject.call( this ); - - this.renderable = true; -} - -// constructor -PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; - -/** - * If this object is being rendered by a CanvasRenderer it will call this callback - * - * @method renderCanvas - * @param renderer {CanvasRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback to initialize - * - * @method initWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.initWebGL = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback - * - * @method renderWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) -{ - // not sure if both needed? but ya have for now! - // override! -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; - -/** - * A texture stores the information that represents an image. All textures have a base texture - * - * @class BaseTexture - * @uses EventTarget - * @constructor - * @param source {String} the source object (image or canvas) - */ -PIXI.BaseTexture = function(source) -{ - PIXI.EventTarget.call( this ); - - /** - * [read-only] The width of the base texture set when the image has loaded - * - * @property width - * @type Number - * @readOnly - */ - this.width = 100; - - /** - * [read-only] The height of the base texture set when the image has loaded - * - * @property height - * @type Number - * @readOnly - */ - this.height = 100; - - /** - * [read-only] Describes if the base texture has loaded or not - * - * @property hasLoaded - * @type Boolean - * @readOnly - */ - this.hasLoaded = false; - - /** - * The source that is loaded to create the texture - * - * @property source - * @type Image - */ - this.source = source; - - if(!source)return; - - if(this.source instanceof Image || this.source instanceof HTMLImageElement) - { - if(this.source.complete) - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - else - { - - var scope = this; - this.source.onload = function(){ - - scope.hasLoaded = true; - scope.width = scope.source.width; - scope.height = scope.source.height; - - // add it to somewhere... - PIXI.texturesToUpdate.push(scope); - scope.dispatchEvent( { type: 'loaded', content: scope } ); - } - // this.image.src = imageUrl; - } - } - else - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - - this._powerOf2 = false; -} - -PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; - -/** - * Destroys this base texture - * - * @method destroy - */ -PIXI.BaseTexture.prototype.destroy = function() -{ - if(this.source instanceof Image) - { - this.source.src = null; - } - this.source = null; - PIXI.texturesToDestroy.push(this); -} - -/** - * Helper function that returns a base texture based on an image url - * If the image is not in the base texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @return BaseTexture - */ -PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) -{ - var baseTexture = PIXI.BaseTextureCache[imageUrl]; - if(!baseTexture) - { - // new Image() breaks tex loading in some versions of Chrome. - // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); - if (crossorigin) - { - image.crossOrigin = ''; - } - image.src = imageUrl; - baseTexture = new PIXI.BaseTexture(image); - PIXI.BaseTextureCache[imageUrl] = baseTexture; - } - - return baseTexture; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.TextureCache = {}; -PIXI.FrameCache = {}; - -/** - * A texture stores the information that represents an image or part of an image. It cannot be added - * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used - * - * @class Texture - * @uses EventTarget - * @constructor - * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frame {Rectangle} The rectangle frame of the texture to show - */ -PIXI.Texture = function(baseTexture, frame) -{ - PIXI.EventTarget.call( this ); - - if(!frame) - { - this.noFrame = true; - frame = new PIXI.Rectangle(0,0,1,1); - } - - if(baseTexture instanceof PIXI.Texture) - baseTexture = baseTexture.baseTexture; - - /** - * The base texture of this texture - * - * @property baseTexture - * @type BaseTexture - */ - this.baseTexture = baseTexture; - - /** - * The frame specifies the region of the base texture that this texture uses - * - * @property frame - * @type Rectangle - */ - this.frame = frame; - - /** - * The trim point - * - * @property trim - * @type Point - */ - this.trim = new PIXI.Point(); - - this.scope = this; - - if(baseTexture.hasLoaded) - { - if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - //console.log(frame) - - this.setFrame(frame); - } - else - { - var scope = this; - baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); - } -} - -PIXI.Texture.prototype.constructor = PIXI.Texture; - -/** - * Called when the base texture is loaded - * - * @method onBaseTextureLoaded - * @param event - * @private - */ -PIXI.Texture.prototype.onBaseTextureLoaded = function(event) -{ - var baseTexture = this.baseTexture; - baseTexture.removeEventListener( 'loaded', this.onLoaded ); - - if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - this.noFrame = false; - this.width = this.frame.width; - this.height = this.frame.height; - - this.scope.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Destroys this texture - * - * @method destroy - * @param destroyBase {Boolean} Whether to destroy the base texture as well - */ -PIXI.Texture.prototype.destroy = function(destroyBase) -{ - if(destroyBase)this.baseTexture.destroy(); -} - -/** - * Specifies the rectangle region of the baseTexture - * - * @method setFrame - * @param frame {Rectangle} The frame of the texture to set it to - */ -PIXI.Texture.prototype.setFrame = function(frame) -{ - this.frame = frame; - this.width = frame.width; - this.height = frame.height; - - 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); - } - - this.updateFrame = true; - - PIXI.Texture.frameUpdates.push(this); - //this.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Helper function that returns a texture based on an image url - * If the image is not in the texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - * @return Texture - */ -PIXI.Texture.fromImage = function(imageUrl, crossorigin) -{ - var texture = PIXI.TextureCache[imageUrl]; - - if(!texture) - { - texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); - PIXI.TextureCache[imageUrl] = texture; - } - - return texture; -} - -/** - * Helper function that returns a texture based on a frame id - * If the frame id is not in the texture cache an error will be thrown - * - * @static - * @method fromFrame - * @param frameId {String} The frame id of the texture - * @return Texture - */ -PIXI.Texture.fromFrame = function(frameId) -{ - var texture = PIXI.TextureCache[frameId]; - if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); - return texture; -} - -/** - * Helper function that returns a texture based on a canvas element - * If the canvas is not in the texture cache it will be created and loaded - * - * @static - * @method fromCanvas - * @param canvas {Canvas} The canvas element source of the texture - * @return Texture - */ -PIXI.Texture.fromCanvas = function(canvas) -{ - var baseTexture = new PIXI.BaseTexture(canvas); - return new PIXI.Texture(baseTexture); -} - - -/** - * Adds a texture to the textureCache. - * - * @static - * @method addTextureToCache - * @param texture {Texture} - * @param id {String} the id that the texture will be stored against. - */ -PIXI.Texture.addTextureToCache = function(texture, id) -{ - PIXI.TextureCache[id] = texture; -} - -/** - * Remove a texture from the textureCache. - * - * @static - * @method removeTextureFromCache - * @param id {String} the id of the texture to be removed - * @return {Texture} the texture that was removed - */ -PIXI.Texture.removeTextureFromCache = function(id) -{ - var texture = PIXI.TextureCache[id] - PIXI.TextureCache[id] = null; - return texture; -} - -// this is more for webGL.. it contains updated frames.. -PIXI.Texture.frameUpdates = []; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. - - __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. - Otherwise black rectangles will be drawn instead. - - RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: - - var renderTexture = new PIXI.RenderTexture(800, 600); - var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); - sprite.position.x = 800/2; - sprite.position.y = 600/2; - sprite.anchor.x = 0.5; - sprite.anchor.y = 0.5; - renderTexture.render(sprite); - - Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: - - var doc = new PIXI.DisplayObjectContainer(); - doc.addChild(sprite); - renderTexture.render(doc); // Renders to center of renderTexture - - @class RenderTexture - @extends Texture - @constructor - @param width {Number} The width of the render texture - @param height {Number} The height of the render texture - */ -PIXI.RenderTexture = function(width, height) -{ - PIXI.EventTarget.call( this ); - - this.width = width || 100; - this.height = height || 100; - - this.indetityMatrix = PIXI.mat3.create(); - - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - if(PIXI.gl) - { - this.initWebGL(); - } - else - { - this.initCanvas(); - } -} - -PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); -PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; - -/** - * Initializes the webgl data for this texture - * - * @method initWebGL - * @private - */ -PIXI.RenderTexture.prototype.initWebGL = function() -{ - var gl = PIXI.gl; - this.glFramebuffer = gl.createFramebuffer(); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - this.glFramebuffer.width = this.width; - this.glFramebuffer.height = this.height; - - this.baseTexture = new PIXI.BaseTexture(); - - this.baseTexture.width = this.width; - this.baseTexture.height = this.height; - - this.baseTexture._glTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - - this.baseTexture.isRender = true; - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); - - // create a projection matrix.. - this.projection = new PIXI.Point(this.width/2 , -this.height/2); - - // set the correct render function.. - this.render = this.renderWebGL; -} - - -PIXI.RenderTexture.prototype.resize = function(width, height) -{ - - this.width = width; - this.height = height; - - if(PIXI.gl) - { - this.projection.x = this.width/2 - this.projection.y = -this.height/2; - - var gl = PIXI.gl; - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - } - else - { - - this.frame.width = this.width - this.frame.height = this.height; - this.renderer.resize(this.width, this.height); - } -} - -/** - * Initializes the canvas data for this texture - * - * @method initCanvas - * @private - */ -PIXI.RenderTexture.prototype.initCanvas = function() -{ - this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); - - this.baseTexture = new PIXI.BaseTexture(this.renderer.view); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - this.render = this.renderCanvas; -} - -/** - * This function will draw the display object to the texture. - * - * @method renderWebGL - * @param displayObject {DisplayObject} The display object to render this texture on - * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn - * @private - */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) -{ - var gl = PIXI.gl; - - // enable the alpha color mask.. - gl.colorMask(true, true, true, true); - - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - if(clear) - { - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } - - // THIS WILL MESS WITH HIT TESTING! - var children = displayObject.children; - - //TODO -? create a new one??? dont think so! - var originalWorldTransform = displayObject.worldTransform; - displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; - // modify to flip... - displayObject.worldTransform[4] = -1; - displayObject.worldTransform[5] = this.projection.y * -2; - - if(position) - { - displayObject.worldTransform[2] = position.x; - displayObject.worldTransform[5] -= position.y; - } - - PIXI.visibleCount++; - displayObject.vcount = PIXI.visibleCount; - - for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded - * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported - * sprite sheet data formats only include "JSON" at this time. Supported bitmap font - * data formats include "xml" and "fnt". - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.AssetLoader = function(assetURLs, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The array of asset URLs that are going to be loaded - * - * @property assetURLs - * @type Array - */ - this.assetURLs = assetURLs; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * Maps file extension to loader types - * - * @property loadersByType - * @type Object - */ - this.loadersByType = { - "jpg": PIXI.ImageLoader, - "jpeg": PIXI.ImageLoader, - "png": PIXI.ImageLoader, - "gif": PIXI.ImageLoader, - "json": PIXI.JsonLoader, - "anim": PIXI.SpineLoader, - "xml": PIXI.BitmapFontLoader, - "fnt": PIXI.BitmapFontLoader - }; - - -}; - -/** - * Fired when an item has loaded - * @event onProgress - */ - -/** - * Fired when all the assets have loaded - * @event onComplete - */ - -// constructor -PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; - -/** - * Starts loading the assets sequentially - * - * @method load - */ -PIXI.AssetLoader.prototype.load = function() -{ - var scope = this; - - this.loadCount = this.assetURLs.length; - - for (var i=0; i < this.assetURLs.length; i++) - { - var fileName = this.assetURLs[i]; - var fileType = fileName.split(".").pop().toLowerCase(); - - var loaderClass = this.loadersByType[fileType]; - if(!loaderClass) - throw new Error(fileType + " is an unsupported file type"); - - var loader = new loaderClass(fileName, this.crossorigin); - - loader.addEventListener("loaded", function() - { - scope.onAssetLoaded(); - }); - loader.load(); - } -}; - -/** - * Invoked after each file is loaded - * - * @method onAssetLoaded - * @private - */ -PIXI.AssetLoader.prototype.onAssetLoaded = function() -{ - this.loadCount--; - this.dispatchEvent({type: "onProgress", content: this}); - if(this.onProgress) this.onProgress(); - - if(this.loadCount == 0) - { - this.dispatchEvent({type: "onComplete", content: this}); - if(this.onComplete) this.onComplete(); - } -}; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The json file loader is used to load in JSON data and parsing it - * When loaded this class will dispatch a "loaded" event - * If load failed this class will dispatch a "error" event - * - * @class JsonLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.JsonLoader = function (url, crossorigin) { - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * [read-only] Whether the data has loaded yet - * - * @property loaded - * @type Boolean - * @readOnly - */ - this.loaded = false; - -}; - -// constructor -PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; - -/** - * Loads the JSON data - * - * @method load - */ -PIXI.JsonLoader.prototype.load = function () { - this.ajaxRequest = new AjaxRequest(); - var scope = this; - this.ajaxRequest.onreadystatechange = function () { - scope.onJSONLoaded(); - }; - - this.ajaxRequest.open("GET", this.url, true); - if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); - this.ajaxRequest.send(null); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.JsonLoader.prototype.onJSONLoaded = function () { - if (this.ajaxRequest.readyState == 4) { - if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { - this.json = JSON.parse(this.ajaxRequest.responseText); - - if(this.json.frames) - { - // sprite sheet - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); - - } - else if(this.json.bones) - { - // spine animation - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - PIXI.AnimCache[this.url] = skeletonData; - this.onLoaded(); - } - else - { - this.onLoaded(); - } - } - else - { - this.onError(); - } - } -}; - -/** - * Invoke when json file loaded - * - * @method onLoaded - * @private - */ -PIXI.JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * Invoke when error occured - * - * @method onError - * @private - */ -PIXI.JsonLoader.prototype.onError = function () { - this.dispatchEvent({ - type: "error", - content: this - }); -}; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The sprite sheet loader is used to load in JSON sprite sheet data - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format - * There is a free version so thats nice, although the paid version is great value for money. - * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * This loader will also load the image file that the Spritesheet points to as well as the data. - * When loaded this class will dispatch a "loaded" event - * - * @class SpriteSheetLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ - -PIXI.SpriteSheetLoader = function (url, crossorigin) { - /* - * i use texture packer to load the assets.. - * http://www.codeandweb.com/texturepacker - * make sure to set the format as "JSON" - */ - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = null; - - /** - * The frames of the sprite sheet - * - * @property frames - * @type Object - */ - this.frames = {}; -}; - -// constructor -PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; - -/** - * This will begin loading the JSON file - * - * @method load - */ -PIXI.SpriteSheetLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); - jsonLoader.addEventListener("loaded", function (event) { - scope.json = event.content.json; - scope.onJSONLoaded(); - }); - jsonLoader.load(); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); -}; -/** - * Invoke when all files are loaded (json and texture) - * - * @method onLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onLoaded = function () { - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") - * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * When loaded this class will dispatch a 'loaded' event - * - * @class ImageLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the image - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.ImageLoader = function(url, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = PIXI.Texture.fromImage(url, crossorigin); - - /** - * if the image is loaded with loadFramedSpriteSheet - * frames will contain the sprite sheet frames - * - */ - this.frames = []; -}; - -// constructor -PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; - -/** - * Loads image or takes it from cache - * - * @method load - */ -PIXI.ImageLoader.prototype.load = function() -{ - if(!this.texture.baseTexture.hasLoaded) - { - var scope = this; - this.texture.baseTexture.addEventListener("loaded", function() - { - scope.onLoaded(); - }); - } - else - { - this.onLoaded(); - } -}; - -/** - * Invoked when image file is loaded or it is already cached and ready to use - * - * @method onLoaded - * @private - */ -PIXI.ImageLoader.prototype.onLoaded = function() -{ - this.dispatchEvent({type: "loaded", content: this}); -}; - -/** - * Loads image and split it to uniform sized frames - * - * - * @method loadFramedSpriteSheet - * @param frameWidth {Number} with of each frame - * @param frameHeight {Number} height of each frame - * @param textureName {String} if given, the frames will be cached in - format - */ -PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) -{ - this.frames = []; - var cols = Math.floor(this.texture.width / frameWidth); - var rows = Math.floor(this.texture.height / frameHeight); - - var i=0; - for (var y=0; y= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +} + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + + +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array)) + points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(typeof points[0] === 'number') { + var p = []; + for(var i = 0, il = points.length; i < il; i+=2) { + p.push( + new PIXI.Point(points[i], points[i + 1]) + ); + } + + points = p; + } + + this.points = points; +} + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = []; + for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +} + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; + +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayobjects + * + * @class Circle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +} + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +} + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + + +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayobjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +} + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + //and a radius of 0.5 + var normx = ((x - this.x) / this.width) - 0.5, + normy = ((y - this.y) / this.height) - 0.5; + + normx *= normx; + normy *= normy; + + return (normx + normy < 0.25); +} + +PIXI.Ellipse.getBounds = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +} + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; + + + +/* + * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV + * you both rock! + */ + +function determineMatrixArrayType() { + PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + return PIXI.Matrix; +} + +determineMatrixArrayType(); + +PIXI.mat3 = {}; + +PIXI.mat3.create = function() +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat3.identity = function(matrix) +{ + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat4 = {}; + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat3.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[3], a11 = mat[4], a12 = mat[5], + a20 = mat[6], a21 = mat[7], a22 = mat[8], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], + b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], + b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22; + + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; + dest[4] = b10 * a01 + b11 * a11 + b12 * a21; + dest[5] = b10 * a02 + b11 * a12 + b12 * a22; + + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; + dest[7] = b20 * a01 + b21 * a11 + b22 * a21; + dest[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return dest; +} + +PIXI.mat3.clone = function(mat) +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = mat[0]; + matrix[1] = mat[1]; + matrix[2] = mat[2]; + matrix[3] = mat[3]; + matrix[4] = mat[4]; + matrix[5] = mat[5]; + matrix[6] = mat[6]; + matrix[7] = mat[7]; + matrix[8] = mat[8]; + + return matrix; +} + +PIXI.mat3.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +} + +PIXI.mat3.toMat4 = function (mat, dest) +{ + if (!dest) { dest = PIXI.mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +} + + +///// + + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat4.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) + { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +} + +PIXI.mat4.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; + var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; + var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + // Cache only the current line of the second matrix + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[4]; + b1 = mat2[5]; + b2 = mat2[6]; + b3 = mat2[7]; + dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[8]; + b1 = mat2[9]; + b2 = mat2[10]; + b3 = mat2[11]; + dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[12]; + b1 = mat2[13]; + b2 = mat2[14]; + b3 = mat2[15]; + dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + return dest; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The base class for all objects that are rendered on the screen. + * + * @class DisplayObject + * @constructor + */ +PIXI.DisplayObject = function() +{ + this.last = this; + this.first = this; + /** + * The coordinate of the object relative to the local coordinates of the parent. + * + * @property position + * @type Point + */ + this.position = new PIXI.Point(); + + /** + * The scale factor of the object. + * + * @property scale + * @type Point + */ + this.scale = new PIXI.Point(1,1);//{x:1, y:1}; + + /** + * The pivot point of the displayObject that it rotates around + * + * @property pivot + * @type Point + */ + this.pivot = new PIXI.Point(0,0); + + /** + * The rotation of the object in radians. + * + * @property rotation + * @type Number + */ + this.rotation = 0; + + /** + * The opacity of the object. + * + * @property alpha + * @type Number + */ + this.alpha = 1; + + /** + * The visibility of the object. + * + * @property visible + * @type Boolean + */ + this.visible = true; + + /** + * This is the defined area that will pick up mouse / touch events. It is null by default. + * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) + * + * @property hitArea + * @type Rectangle|Circle|Ellipse|Polygon + */ + this.hitArea = null; + + /** + * This is used to indicate if the displayObject should display a mouse hand cursor on rollover + * + * @property buttonMode + * @type Boolean + */ + this.buttonMode = false; + + /** + * Can this object be rendered + * + * @property renderable + * @type Boolean + */ + this.renderable = false; + + /** + * [read-only] The display object container that contains this display object. + * + * @property parent + * @type DisplayObjectContainer + * @readOnly + */ + this.parent = null; + + /** + * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. + * + * @property stage + * @type Stage + * @readOnly + */ + this.stage = null; + + /** + * [read-only] The multiplied alpha of the displayobject + * + * @property worldAlpha + * @type Number + * @readOnly + */ + this.worldAlpha = 1; + + /** + * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property + * + * @property _interactive + * @type Boolean + * @readOnly + * @private + */ + this._interactive = false; + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [read-only] Current transform of the object locally + * + * @property localTransform + * @type Mat3 + * @readOnly + * @private + */ + this.localTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [NYI] Unkown + * + * @property color + * @type Array<> + * @private + */ + this.color = []; + + /** + * [NYI] Holds whether or not this object is dynamic, for rendering optimization + * + * @property dynamic + * @type Boolean + * @private + */ + this.dynamic = true; + + // chach that puppy! + this._sr = 0; + this._cr = 1; + + + this.filterArea = new PIXI.Rectangle(0,0,1,1); + + /* + * MOUSE Callbacks + */ + + /** + * A callback that is used when the users clicks on the displayObject with their mouse + * @method click + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user clicks the mouse down over the sprite + * @method mousedown + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject + * for this callback to be fired the mouse must have been pressed down over the displayObject + * @method mouseup + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject + * for this callback to be fired, The touch must have started over the displayObject + * @method mouseupoutside + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse rolls over the displayObject + * @method mouseover + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse leaves the displayObject + * @method mouseout + * @param interactionData {InteractionData} + */ + + + /* + * TOUCH Callbacks + */ + + /** + * A callback that is used when the users taps on the sprite with their finger + * basically a touch version of click + * @method tap + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user touch's over the displayObject + * @method touchstart + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases a touch over the displayObject + * @method touchend + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the touch that was over the displayObject + * for this callback to be fired, The touch must have started over the sprite + * @method touchendoutside + * @param interactionData {InteractionData} + */ +} + +// constructor +PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; + +/** + * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default + * Instead of using this function you can now simply set the interactive property to true or false + * + * @method setInteractive + * @param interactive {Boolean} + * @deprecated Simply set the `interactive` property directly + */ +PIXI.DisplayObject.prototype.setInteractive = function(interactive) +{ + this.interactive = interactive; +} + +/** + * Indicates if the sprite will have touch and mouse interactivity. It is false by default + * + * @property interactive + * @type Boolean + * @default false + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { + get: function() { + return this._interactive; + }, + set: function(value) { + this._interactive = value; + + // TODO more to be done here.. + // need to sort out a re-crawl! + if(this.stage)this.stage.dirty = true; + } +}); + +/** + * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. + * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. + * To remove a mask, set this property to null. + * + * @property mask + * @type Graphics + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { + get: function() { + return this._mask; + }, + set: function(value) { + + + if(value) + { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. + * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. + * To remove filters simply set this property to 'null' + * @property filters + * @type Array An array of filters + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + if(value) + { + if(this._filters)this.removeFilter(this._filters); + this.addFilter(value); + + // now put all the passes in one place.. + var passes = []; + for (var i = 0; i < value.length; i++) + { + var filterPasses = value[i].passes; + for (var j = 0; j < filterPasses.length; j++) + { + passes.push(filterPasses[j]); + }; + }; + + value.start.filterPasses = passes; + } + else + { + if(this._filters)this.removeFilter(this._filters); + } + + this._filters = value; + + + + + } +}); + +/* + * Adds a filter to this displayObject + * + * @method addFilter + * @param mask {Graphics} the graphics object to use as a filter + * @private + */ +PIXI.DisplayObject.prototype.addFilter = function(data) +{ + //if(this.filter)return; + //this.filter = true; +// data[0].target = this; + + + // insert a filter block.. + // TODO Onject pool thease bad boys.. + var start = new PIXI.FilterBlock(); + var end = new PIXI.FilterBlock(); + + data.start = start; + data.end = end; + + start.data = data; + end.data = data; + + start.first = start.last = this; + end.first = end.last = this; + + start.open = true; + + start.target = this; + + /* + * insert start + */ + + var childFirst = start + var childLast = start + var nextObject; + var previousObject; + + previousObject = this.first._iPrev; + + if(previousObject) + { + nextObject = previousObject._iNext; + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + } + else + { + nextObject = this; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + + // now insert the end filter block.. + + /* + * insert end filter + */ + var childFirst = end + var childLast = end + var nextObject = null; + var previousObject = null; + + previousObject = this.last; + nextObject = previousObject._iNext; + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + var updateLast = this; + + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = end; + } + updateLast = updateLast.parent; + } + + this.first = start; + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.addFilterBlocks(start, end); + } + +} + +/* + * Removes the filter to this displayObject + * + * @method removeFilter + * @private + */ +PIXI.DisplayObject.prototype.removeFilter = function(data) +{ + //if(!this.filter)return; + //this.filter = false; + // console.log("YUOIO") + // modify the list.. + var startBlock = data.start; + + + var nextObject = startBlock._iNext; + var previousObject = startBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + if(previousObject)previousObject._iNext = nextObject; + + this.first = startBlock._iNext; + + // remove the end filter + var lastBlock = data.end; + + var nextObject = lastBlock._iNext; + var previousObject = lastBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + // this is always true too! + var tempLast = lastBlock._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == lastBlock) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); + } +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObject.prototype.updateTransform = function() +{ + // TODO OPTIMIZE THIS!! with dirty + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + var localTransform = this.localTransform; + var parentTransform = this.parent.worldTransform; + var worldTransform = this.worldTransform; + //console.log(localTransform) + localTransform[0] = this._cr * this.scale.x; + localTransform[1] = -this._sr * this.scale.y + localTransform[3] = this._sr * this.scale.x; + localTransform[4] = this._cr * this.scale.y; + + // TODO --> do we even need a local matrix??? + + var px = this.pivot.x; + var py = this.pivot.y; + + // Cache the matrix values (makes for huge speed increases!) + var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], + a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], + + b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], + b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; + + localTransform[2] = a02 + localTransform[5] = a12 + + worldTransform[0] = b00 * a00 + b01 * a10; + worldTransform[1] = b00 * a01 + b01 * a11; + worldTransform[2] = b00 * a02 + b01 * a12 + b02; + + worldTransform[3] = b10 * a00 + b11 * a10; + worldTransform[4] = b10 * a01 + b11 * a11; + worldTransform[5] = b10 * a02 + b11 * a12 + b12; + + // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! + // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); + this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; + +} + +PIXI.visibleCount = 0; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A DisplayObjectContainer represents a collection of display objects. + * It is the base class of all display objects that act as a container for other objects. + * + * @class DisplayObjectContainer + * @extends DisplayObject + * @constructor + */ +PIXI.DisplayObjectContainer = function() +{ + PIXI.DisplayObject.call( this ); + + /** + * [read-only] The of children of this container. + * + * @property children + * @type Array + * @readOnly + */ + this.children = []; +} + +// constructor +PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; + +/** + * Adds a child to the container. + * + * @method addChild + * @param child {DisplayObject} The DisplayObject to add to the container + */ +PIXI.DisplayObjectContainer.prototype.addChild = function(child) +{ + if(child.parent != undefined) + { + + //// COULD BE THIS??? + child.parent.removeChild(child); + // return; + } + + child.parent = this; + + this.children.push(child); + + // update the stage refference.. + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // LINKED LIST // + + // modify the list.. + var childFirst = child.first + var childLast = child.last; + var nextObject; + var previousObject; + + // this could be wrong if there is a filter?? + if(this._filters || this._mask) + { + previousObject = this.last._iPrev; + } + else + { + previousObject = this.last; + } + + nextObject = previousObject._iNext; + + // always true in this case + // need to make sure the parents last is updated too + var updateLast = this; + var prevLast = previousObject; + + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + +} + +/** + * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown + * + * @method addChildAt + * @param child {DisplayObject} The child to add + * @param index {Number} The index to place the child in + */ +PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) +{ + if(index >= 0 && index <= this.children.length) + { + if(child.parent != undefined) + { + child.parent.removeChild(child); + } + child.parent = this; + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + var nextObject; + var previousObject; + + if(index == this.children.length) + { + previousObject = this.last; + var updateLast = this; + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + } + else if(index == 0) + { + previousObject = this; + } + else + { + previousObject = this.children[index-1].last; + } + + nextObject = previousObject._iNext; + + // always true in this case + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + this.children.splice(index, 0, child); + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + + } + else + { + throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); + } +} + +/** + * [NYI] Swaps the depth of 2 displayObjects + * + * @method swapChildren + * @param child {DisplayObject} + * @param child2 {DisplayObject} + * @private + */ +PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) +{ + /* + * this funtion needs to be recoded.. + * can be done a lot faster.. + */ + return; + + // need to fix this function :/ + /* + // TODO I already know this?? + var index = this.children.indexOf( child ); + var index2 = this.children.indexOf( child2 ); + + if ( index !== -1 && index2 !== -1 ) + { + // cool + + /* + if(this.stage) + { + // this is to satisfy the webGL batching.. + // TODO sure there is a nicer way to achieve this! + this.stage.__removeChild(child); + this.stage.__removeChild(child2); + + this.stage.__addChild(child); + this.stage.__addChild(child2); + } + + // swap the positions.. + this.children[index] = child2; + this.children[index2] = child; + + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + }*/ +} + +/** + * Returns the Child at the specified index + * + * @method getChildAt + * @param index {Number} The index to get the child from + */ +PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) +{ + if(index >= 0 && index < this.children.length) + { + return this.children[index]; + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + } +} + +/** + * Removes a child from the container. + * + * @method removeChild + * @param child {DisplayObject} The DisplayObject to remove + */ +PIXI.DisplayObjectContainer.prototype.removeChild = function(child) +{ + var index = this.children.indexOf( child ); + if ( index !== -1 ) + { + // unlink // + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + + var nextObject = childLast._iNext; + var previousObject = childFirst._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + if(this.last == childLast) + { + var tempLast = childFirst._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == childLast.last) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + } + + childLast._iNext = null; + childFirst._iPrev = null; + + // update the stage reference.. + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = null; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // webGL trim + if(child.__renderGroup) + { + child.__renderGroup.removeDisplayObjectAndChildren(child); + } + + child.parent = undefined; + this.children.splice( index, 1 ); + } + else + { + throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); + } +} + +/* + * Updates the container's children's transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObjectContainer.prototype.updateTransform = function() +{ + if(!this.visible)return; + + PIXI.DisplayObject.prototype.updateTransform.call( this ); + + for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation + */ +PIXI.MovieClip = function(textures) +{ + PIXI.Sprite.call(this, textures[0]); + + /** + * The array of textures that make up the animation + * + * @property textures + * @type Array + */ + this.textures = textures; + + /** + * The speed that the MovieClip will play at. Higher is faster, lower is slower + * + * @property animationSpeed + * @type Number + * @default 1 + */ + this.animationSpeed = 1; + + /** + * Whether or not the movie clip repeats after playing. + * + * @property loop + * @type Boolean + * @default true + */ + this.loop = true; + + /** + * Function to call when a MovieClip finishes playing + * + * @property onComplete + * @type Function + */ + this.onComplete = null; + + /** + * [read-only] The index MovieClips current frame (this may not have to be a whole number) + * + * @property currentFrame + * @type Number + * @default 0 + * @readOnly + */ + this.currentFrame = 0; + + /** + * [read-only] Indicates if the MovieClip is currently playing + * + * @property playing + * @type Boolean + * @readOnly + */ + this.playing = false; +} + +// constructor +PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); +PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; + +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + +/** + * Stops the MovieClip + * + * @method stop + */ +PIXI.MovieClip.prototype.stop = function() +{ + this.playing = false; +} + +/** + * Plays the MovieClip + * + * @method play + */ +PIXI.MovieClip.prototype.play = function() +{ + this.playing = true; +} + +/** + * Stops the MovieClip and goes to a specific frame + * + * @method gotoAndStop + * @param frameNumber {Number} frame index to stop at + */ +PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) +{ + this.playing = false; + this.currentFrame = frameNumber; + var round = (this.currentFrame + 0.5) | 0; + this.setTexture(this.textures[round % this.textures.length]); +} + +/** + * Goes to a specific frame and begins playing the MovieClip + * + * @method gotoAndPlay + * @param frameNumber {Number} frame index to start at + */ +PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) +{ + this.currentFrame = frameNumber; + this.playing = true; +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.MovieClip.prototype.updateTransform = function() +{ + PIXI.Sprite.prototype.updateTransform.call(this); + + if(!this.playing)return; + + this.currentFrame += this.animationSpeed; + + var round = (this.currentFrame + 0.5) | 0; + + if(this.loop || round < this.textures.length) + { + this.setTexture(this.textures[round % this.textures.length]); + } + else if(round >= this.textures.length) + { + this.gotoAndStop(this.textures.length - 1); + if(this.onComplete) + { + this.onComplete(); + } + } +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + + +PIXI.FilterBlock = function() +{ + this.visible = true; + this.renderable = true; +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text to split a line you can use "\n" + * + * @class Text + * @extends Sprite + * @constructor + * @param text {String} The copy that you would like the text to display + * @param [style] {Object} The style parameters + * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text = function(text, style) +{ + this.canvas = document.createElement("canvas"); + this.context = this.canvas.getContext("2d"); + PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); + + this.setText(text); + this.setStyle(style); + + this.updateText(); + this.dirty = false; +}; + +// constructor +PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); +PIXI.Text.prototype.constructor = PIXI.Text; + +/** + * Set the style of the text + * + * @method setStyle + * @param [style] {Object} The style parameters + * @param [style.font="bold 20pt Arial"] {String} The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text.prototype.setStyle = function(style) +{ + style = style || {}; + style.font = style.font || "bold 20pt Arial"; + style.fill = style.fill || "black"; + style.align = style.align || "left"; + style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 + style.strokeThickness = style.strokeThickness || 0; + style.wordWrap = style.wordWrap || false; + style.wordWrapWidth = style.wordWrapWidth || 100; + this.style = style; + this.dirty = true; +}; + +/** + * Set the copy for the text object. To split a line you can use "\n" + * + * @methos setText + * @param {String} text The copy that you would like the text to display + */ +PIXI.Text.prototype.setText = function(text) +{ + this.text = text.toString() || " "; + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.Text.prototype.updateText = function() +{ + this.context.font = this.style.font; + + var outputText = this.text; + + // word wrap + // preserve original text + if(this.style.wordWrap)outputText = this.wordWrap(this.text); + + //split text into lines + var lines = outputText.split(/(?:\r\n|\r|\n)/); + + //calculate text width + var lineWidths = []; + var maxLineWidth = 0; + for (var i = 0; i < lines.length; i++) + { + var lineWidth = this.context.measureText(lines[i]).width; + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + this.canvas.width = maxLineWidth + this.style.strokeThickness; + + //calculate text height + var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; + this.canvas.height = lineHeight * lines.length; + + //set canvas text styles + this.context.fillStyle = this.style.fill; + this.context.font = this.style.font; + + this.context.strokeStyle = this.style.stroke; + this.context.lineWidth = this.style.strokeThickness; + + this.context.textBaseline = "top"; + + //draw lines line by line + for (i = 0; i < lines.length; i++) + { + var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); + + if(this.style.align == "right") + { + linePosition.x += maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + linePosition.x += (maxLineWidth - lineWidths[i]) / 2; + } + + if(this.style.stroke && this.style.strokeThickness) + { + this.context.strokeText(lines[i], linePosition.x, linePosition.y); + } + + if(this.style.fill) + { + this.context.fillText(lines[i], linePosition.x, linePosition.y); + } + } + + this.updateTexture(); +}; + +/** + * Updates texture size based on canvas size + * + * @method updateTexture + * @private + */ +PIXI.Text.prototype.updateTexture = function() +{ + this.texture.baseTexture.width = this.canvas.width; + this.texture.baseTexture.height = this.canvas.height; + this.texture.frame.width = this.canvas.width; + this.texture.frame.height = this.canvas.height; + + this._width = this.canvas.width; + this._height = this.canvas.height; + + PIXI.texturesToUpdate.push(this.texture.baseTexture); +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.Text.prototype.updateTransform = function() +{ + if(this.dirty) + { + this.updateText(); + this.dirty = false; + } + + PIXI.Sprite.prototype.updateTransform.call(this); +}; + +/* + * http://stackoverflow.com/users/34441/ellisbben + * great solution to the problem! + * + * @method determineFontHeight + * @param fontStyle {Object} + * @private + */ +PIXI.Text.prototype.determineFontHeight = function(fontStyle) +{ + // build a little reference dictionary so if the font style has been used return a + // cached version... + var result = PIXI.Text.heightCache[fontStyle]; + + if(!result) + { + var body = document.getElementsByTagName("body")[0]; + var dummy = document.createElement("div"); + var dummyText = document.createTextNode("M"); + dummy.appendChild(dummyText); + dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); + body.appendChild(dummy); + + result = dummy.offsetHeight; + PIXI.Text.heightCache[fontStyle] = result; + + body.removeChild(dummy); + } + + return result; +}; + +/** + * Applies newlines to a string to have it optimally fit into the horizontal + * bounds set by the Text object's wordWrapWidth property. + * + * @method wordWrap + * @param text {String} + * @private + */ +PIXI.Text.prototype.wordWrap = function(text) +{ + // Greedy wrapping algorithm that will wrap words as the line grows longer + // than its horizontal bounds. + var result = ""; + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) + { + var spaceLeft = this.style.wordWrapWidth; + var words = lines[i].split(" "); + for (var j = 0; j < words.length; j++) + { + var wordWidth = this.context.measureText(words[j]).width; + var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; + if(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 = this.style.wordWrapWidth - wordWidth; + } + else + { + spaceLeft -= wordWidthWithSpace; + result += words[j] + " "; + } + } + result += "\n"; + } + return result; +}; + +/** + * Destroys this text object + * + * @method destroy + * @param destroyTexture {Boolean} + */ +PIXI.Text.prototype.destroy = function(destroyTexture) +{ + if(destroyTexture) + { + this.texture.destroy(); + } + +}; + +PIXI.Text.heightCache = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" + * You can generate the fnt files using + * http://www.angelcode.com/products/bmfont/ for windows or + * http://www.bmglyph.com/ for mac. + * + * @class BitmapText + * @extends DisplayObjectContainer + * @constructor + * @param text {String} The copy that you would like the text to display + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText = function(text, style) +{ + PIXI.DisplayObjectContainer.call(this); + + this.setText(text); + this.setStyle(style); + this.updateText(); + this.dirty = false + +}; + +// constructor +PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; + +/** + * Set the copy for the text object + * + * @method setText + * @param text {String} The copy that you would like the text to display + */ +PIXI.BitmapText.prototype.setText = function(text) +{ + this.text = text || " "; + this.dirty = true; +}; + +/** + * Set the style of the text + * + * @method setStyle + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText.prototype.setStyle = function(style) +{ + style = style || {}; + style.align = style.align || "left"; + this.style = style; + + var font = style.font.split(" "); + this.fontName = font[font.length - 1]; + this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; + + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.BitmapText.prototype.updateText = function() +{ + var data = PIXI.BitmapText.fonts[this.fontName]; + var pos = new PIXI.Point(); + var prevCharCode = null; + var chars = []; + var maxLineWidth = 0; + var lineWidths = []; + var line = 0; + var scale = this.fontSize / data.size; + for(var i = 0; i < this.text.length; i++) + { + var charCode = this.text.charCodeAt(i); + if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) + { + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + line++; + + pos.x = 0; + pos.y += data.lineHeight; + prevCharCode = null; + continue; + } + + var charData = data.chars[charCode]; + if(!charData) continue; + + if(prevCharCode && charData[prevCharCode]) + { + pos.x += charData.kerning[prevCharCode]; + } + chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); + pos.x += charData.xAdvance; + + prevCharCode = charCode; + } + + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + + var lineAlignOffsets = []; + for(i = 0; i <= line; i++) + { + var alignOffset = 0; + if(this.style.align == "right") + { + alignOffset = maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + alignOffset = (maxLineWidth - lineWidths[i]) / 2; + } + lineAlignOffsets.push(alignOffset); + } + + for(i = 0; i < chars.length; i++) + { + var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); + c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; + c.position.y = chars[i].position.y * scale; + c.scale.x = c.scale.y = scale; + this.addChild(c); + } + + this.width = pos.x * scale; + this.height = (pos.y + data.lineHeight) * scale; +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.BitmapText.prototype.updateTransform = function() +{ + if(this.dirty) + { + while(this.children.length > 0) + { + this.removeChild(this.getChildAt(0)); + } + this.updateText(); + + this.dirty = false; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + +PIXI.BitmapText.fonts = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + /** + * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive + * This manager also supports multitouch. + * + * @class InteractionManager + * @constructor + * @param stage {Stage} The stage to handle interactions + */ +PIXI.InteractionManager = function(stage) +{ + /** + * a refference to the stage + * + * @property stage + * @type Stage + */ + this.stage = stage; + + /** + * the mouse data + * + * @property mouse + * @type InteractionData + */ + this.mouse = new PIXI.InteractionData(); + + /** + * an object that stores current touches (InteractionData) by id reference + * + * @property touchs + * @type Object + */ + this.touchs = {}; + + + + // helpers + this.tempPoint = new PIXI.Point(); + //this.tempMatrix = mat3.create(); + + this.mouseoverEnabled = true; + + //tiny little interactiveData pool! + this.pool = []; + + this.interactiveItems = []; + this.interactionDOMElement = null; + + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + + this.last = 0; +} + +// constructor +PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; + +/** + * Collects an interactive sprite recursively to have their interactions managed + * + * @method collectInteractiveSprite + * @param displayObject {DisplayObject} the displayObject to collect + * @param iParent {DisplayObject} + * @private + */ +PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) +{ + var children = displayObject.children; + var length = children.length; + + /// make an interaction tree... {item.__interactiveParent} + for (var i = length-1; i >= 0; i--) + { + var child = children[i]; + +// if(child.visible) { + // push all interactive bits + if(child.interactive) + { + iParent.interactiveChildren = true; + //child.__iParent = iParent; + this.interactiveItems.push(child); + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, child); + } + } + else + { + child.__iParent = null; + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, iParent); + } + } +// } + } +} + +/** + * Sets the target for event delegation + * + * @method setTarget + * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to + * @private + */ +PIXI.InteractionManager.prototype.setTarget = function(target) +{ + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + + if (window.navigator.msPointerEnabled) + { + // time to remove some of that zoom in ja.. + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; + + // DO some window specific touch! + } + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); +} + + +/** + * updates the state of interactive objects + * + * @method update + * @private + */ +PIXI.InteractionManager.prototype.update = function() +{ + if(!this.target)return; + + // frequency of 30fps?? + var now = Date.now(); + var diff = now - this.last; + diff = (diff * 30) / 1000; + if(diff < 1)return; + this.last = now; + // + + // ok.. so mouse events?? + // yes for now :) + // OPTIMSE - how often to check?? + if(this.dirty) + { + this.dirty = false; + + var len = this.interactiveItems.length; + + for (var i=0; i < len; i++) { + this.interactiveItems[i].interactiveChildren = false; + } + + this.interactiveItems = []; + + if(this.stage.interactive)this.interactiveItems.push(this.stage); + // go through and collect all the objects that are interactive.. + this.collectInteractiveSprite(this.stage, this.stage); + } + + // loop through interactive objects! + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + + //if(!item.visible)continue; + + // OPTIMISATION - only calculate every time if the mousemove function exists.. + // OK so.. does the object have any other interactive functions? + // hit-test the clip! + + + if(item.mouseover || item.mouseout || item.buttonMode) + { + // ok so there are some functions so lets hit test it.. + item.__hit = this.hitTest(item, this.mouse); + this.mouse.target = item; + // ok so deal with interactions.. + // loks like there was a hit! + if(item.__hit) + { + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; + + if(!item.__isOver) + { + + if(item.mouseover)item.mouseover(this.mouse); + item.__isOver = true; + } + } + else + { + if(item.__isOver) + { + // roll out! + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } + } + + // ---> + } +} + +/** + * Is called when the mouse moves accross the renderer element + * + * @method onMouseMove + * @param event {Event} The DOM event of the mouse moving + * @private + */ +PIXI.InteractionManager.prototype.onMouseMove = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + // TODO optimize by not check EVERY TIME! maybe half as often? // + var rect = this.interactionDOMElement.getBoundingClientRect(); + + this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); + this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); + + var length = this.interactiveItems.length; + var global = this.mouse.global; + + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousemove) + { + //call the function! + item.mousemove(this.mouse); + } + } +} + +/** + * Is called when the mouse button is pressed down on the renderer element + * + * @method onMouseDown + * @param event {Event} The DOM event of a mouse button being pressed down + * @private + */ +PIXI.InteractionManager.prototype.onMouseDown = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + // loop through inteaction tree... + // hit test each item! -> + // get interactive items under point?? + //stage.__i + var length = this.interactiveItems.length; + var global = this.mouse.global; + + var index = 0; + var parent = this.stage; + + // while + // hit test + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousedown || item.click) + { + item.__mouseIsDown = true; + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit) + { + //call the function! + if(item.mousedown)item.mousedown(this.mouse); + item.__isDown = true; + + // just the one! + if(!item.interactiveChildren)break; + } + } + } +} + + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + +/** + * Is called when the mouse button is released on the renderer element + * + * @method onMouseUp + * @param event {Event} The DOM event of a mouse button being released + * @private + */ +PIXI.InteractionManager.prototype.onMouseUp = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + var global = this.mouse.global; + + + var length = this.interactiveItems.length; + var up = false; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mouseup || item.mouseupoutside || item.click) + { + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit && !up) + { + //call the function! + if(item.mouseup) + { + item.mouseup(this.mouse); + } + if(item.__isDown) + { + if(item.click)item.click(this.mouse); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.mouseupoutside)item.mouseupoutside(this.mouse); + } + } + + item.__isDown = false; + } + } +} + +/** + * Tests if the current mouse coords hit a sprite + * + * @method hitTest + * @param item {DisplayObject} The displayObject to test for a hit + * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit + * @private + */ +PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) +{ + var global = interactionData.global; + + if(item.vcount !== PIXI.visibleCount)return false; + + var isSprite = (item instanceof PIXI.Sprite), + worldTransform = item.worldTransform, + a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10), + x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; + + interactionData.target = item; + + //a sprite or display object with a hit area defined + if(item.hitArea && item.hitArea.contains) { + if(item.hitArea.contains(x, y)) { + //if(isSprite) + interactionData.target = item; + + return true; + } + + return false; + } + // a sprite with no hitarea defined + else if(isSprite) + { + var width = item.texture.frame.width, + height = item.texture.frame.height, + x1 = -width * item.anchor.x, + y1; + + if(x > x1 && x < x1 + width) + { + y1 = -height * item.anchor.y; + + if(y > y1 && y < y1 + height) + { + // set the target property if a hit is true! + interactionData.target = item + return true; + } + } + } + + var length = item.children.length; + + for (var i = 0; i < length; i++) + { + var tempItem = item.children[i]; + var hit = this.hitTest(tempItem, interactionData); + if(hit) + { + // hmm.. TODO SET CORRECT TARGET? + interactionData.target = item + return true; + } + } + + return false; +} + +/** + * Is called when a touch is moved accross the renderer element + * + * @method onTouchMove + * @param event {Event} The DOM event of a touch moving accross the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchMove = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; + + // update the touch position + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + } + + var length = this.interactiveItems.length; + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + if(item.touchmove)item.touchmove(touchData); + } +} + +/** + * Is called when a touch is started on the renderer element + * + * @method onTouchStart + * @param event {Event} The DOM event of a touch starting on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchStart = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + + var changedTouches = event.changedTouches; + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + + var touchData = this.pool.pop(); + if(!touchData)touchData = new PIXI.InteractionData(); + + touchData.originalEvent = event || window.event; + + this.touchs[touchEvent.identifier] = touchData; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + + if(item.touchstart || item.tap) + { + item.__hit = this.hitTest(item, touchData); + + if(item.__hit) + { + //call the function! + if(item.touchstart)item.touchstart(touchData); + item.__isDown = true; + item.__touchData = touchData; + + if(!item.interactiveChildren)break; + } + } + } + } +} + +/** + * Is called when a touch is ended on the renderer element + * + * @method onTouchEnd + * @param event {Event} The DOM event of a touch ending on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchEnd = function(event) +{ + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + var up = false; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + var itemTouchData = item.__touchData; // <-- Here! + item.__hit = this.hitTest(item, touchData); + + if(itemTouchData == touchData) + { + // so this one WAS down... + touchData.originalEvent = event || window.event; + // hitTest?? + + if(item.touchend || item.tap) + { + if(item.__hit && !up) + { + if(item.touchend)item.touchend(touchData); + if(item.__isDown) + { + if(item.tap)item.tap(touchData); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.touchendoutside)item.touchendoutside(touchData); + } + } + + item.__isDown = false; + } + + item.__touchData = null; + + } + else + { + + } + } + // remove the touch.. + this.pool.push(touchData); + this.touchs[touchEvent.identifier] = null; + } +} + +/** + * Holds all information related to an Interaction event + * + * @class InteractionData + * @constructor + */ +PIXI.InteractionData = function() +{ + /** + * This point stores the global coords of where the touch/mouse event happened + * + * @property global + * @type Point + */ + this.global = new PIXI.Point(); + + // this is here for legacy... but will remove + this.local = new PIXI.Point(); + + /** + * The target Sprite that was interacted with + * + * @property target + * @type Sprite + */ + this.target; + + /** + * When passed to an event handler, this will be the original DOM Event that was captured + * + * @property originalEvent + * @type Event + */ + this.originalEvent; +} + +/** + * This will return the local coords of the specified displayObject for this InteractionData + * + * @method getLocalPosition + * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off + * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject + */ +PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) +{ + var worldTransform = displayObject.worldTransform; + var global = this.global; + + // do a cheeky transform to get the mouse coords; + var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10); + // set the mouse coords... + return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) +} + +// constructor +PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Stage represents the root of the display tree. Everything connected to the stage is rendered + * + * @class Stage + * @extends DisplayObjectContainer + * @constructor + * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format + * like: 0xFFFFFF for white + */ +PIXI.Stage = function(backgroundColor) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create(); + + /** + * Whether or not the stage is interactive + * + * @property interactive + * @type Boolean + */ + this.interactive = true; + + /** + * The interaction manage for this stage, manages all interactive activity on the stage + * + * @property interactive + * @type InteractionManager + */ + this.interactionManager = new PIXI.InteractionManager(this); + + /** + * Whether the stage is dirty and needs to have interactions updated + * + * @property dirty + * @type Boolean + * @private + */ + this.dirty = true; + + this.__childrenAdded = []; + this.__childrenRemoved = []; + + //the stage is it's own stage + this.stage = this; + + //optimize hit detection a bit + this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); + + this.setBackgroundColor(backgroundColor); + this.worldVisible = true; +} + +// constructor +PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Stage.prototype.constructor = PIXI.Stage; + +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Stage.prototype.updateTransform = function() +{ + this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; + + for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + +/** + * A polyfill for Function.prototype.bind + * + * @method bind + */ +if (typeof Function.prototype.bind != 'function') { + Function.prototype.bind = (function () { + var slice = Array.prototype.slice; + return function (thisArg) { + var target = this, boundArgs = slice.call(arguments, 1); + + if (typeof target != 'function') throw new TypeError(); + + function bound() { + var args = boundArgs.concat(slice.call(arguments)); + target.apply(this instanceof bound ? this : thisArg, args); + } + + bound.prototype = (function F(proto) { + proto && (F.prototype = proto); + if (!(this instanceof F)) return new F; + })(target.prototype); + + return bound; + }; + })(); +} + +/** + * A wrapper for ajax requests to be handled cross browser + * + * @class AjaxRequest + * @constructor + */ +var AjaxRequest = PIXI.AjaxRequest = function() +{ + var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE + + if (window.ActiveXObject) + { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) + for (var i=0; i>>>>>>>>") + console.log("_") + var safe = 0; + var tmp = item.first; + console.log(tmp); + + while(tmp._iNext) + { + safe++; + tmp = tmp._iNext; + console.log(tmp); + // console.log(tmp); + + if(safe > 100) + { + console.log("BREAK") + break + } + } +} + + + + + + +/** + * https://github.com/mrdoob/eventtarget.js/ + * THankS mr DOob! + */ + +/** + * Adds event emitter functionality to a class + * + * @class EventTarget + * @example + * function MyEmitter() { + * PIXI.EventTarget.call(this); //mixes in event target stuff + * } + * + * var em = new MyEmitter(); + * em.emit({ type: 'eventName', data: 'some data' }); + */ +PIXI.EventTarget = function () { + + var listeners = {}; + + this.addEventListener = this.on = function ( type, listener ) { + + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + } + + }; + + this.dispatchEvent = this.emit = function ( event ) { + + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + + } + + }; + + this.removeEventListener = this.off = function ( type, listener ) { + + var index = listeners[ type ].indexOf( listener ); + + if ( index !== - 1 ) { + + listeners[ type ].splice( index, 1 ); + + } + + }; + +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * This helper function will automatically detect which renderer you should be using. + * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by + * the browser then this function will return a canvas renderer + * + * @method autoDetectRenderer + * @static + * @param width {Number} the width of the renderers view + * @param height {Number} the height of the renderers view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias + */ +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) +{ + if(!width)width = 800; + if(!height)height = 600; + + // BORROWED from Mr Doob (mrdoob.com) + var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); + + if(webgl) + { + var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); + webgl = !ie; + } + + //console.log(webgl); + if( webgl ) + { + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); + } + + return new PIXI.CanvasRenderer(width, height, view, transparent); +}; + + + +/* + PolyK library + url: http://polyk.ivank.net + Released under MIT licence. + + Copyright (c) 2012 Ivan Kuckir + + 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. + + This is an amazing lib! + + slightly modified by mat groves (matgroves.com); +*/ + +PIXI.PolyK = {}; + +/** + * Triangulates shapes for webGL graphic fills + * + * @method Triangulate + * @namespace PolyK + * @constructor + */ +PIXI.PolyK.Triangulate = function(p) +{ + var sign = true; + + var n = p.length>>1; + if(n<3) return []; + var tgs = []; + var avl = []; + for(var i=0; i 3) + { + var i0 = avl[(i+0)%al]; + var i1 = avl[(i+1)%al]; + var i2 = avl[(i+2)%al]; + + var ax = p[2*i0], ay = p[2*i0+1]; + var bx = p[2*i1], by = p[2*i1+1]; + var cx = p[2*i2], cy = p[2*i2+1]; + + var earFound = false; + if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) + { + earFound = true; + for(var j=0; j 3*al) + { + // need to flip flip reverse it! + // reset! + if(sign) + { + var tgs = []; + avl = []; + for(var i=0; i= 0) && (v >= 0) && (u + v < 1); +} + +/** + * Checks if a shape is convex + * + * @class _convex + * @namespace PolyK + * @private + */ +PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) +{ + return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.initDefaultShaders = function() +{ + PIXI.primitiveShader = new PIXI.PrimitiveShader(); + PIXI.primitiveShader.init(); + + PIXI.stripShader = new PIXI.StripShader(); + PIXI.stripShader.init(); + + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + + var gl = PIXI.gl; + var shaderProgram = PIXI.defaultShader.program; + + + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.activatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.primitiveShader.program); + + gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + + gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); +} + +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + + gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + +} + +PIXI.activateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.stripShader.program); + // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.deactivateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +/* + +SHADER COMPILER HELPERS +*/ + +PIXI.CompileVertexShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); +} + +PIXI.CompileFragmentShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); +} + +PIXI._CompileShader = function(gl, shaderSrc, shaderType) +{ + var src = shaderSrc.join("\n"); + var shader = gl.createShader(shaderType); + gl.shaderSource(shader, src); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} + + +PIXI.compileProgram = function(vertexSrc, fragmentSrc) +{ + var gl = PIXI.gl; + var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); + var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); + + var shaderProgram = gl.createProgram(); + + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialise shaders"); + } + + return shaderProgram; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * @author Richard Davey http://www.photonstorm.com @photonstorm + */ + +/** +* @class PIXI.PixiShader +* @constructor +*/ +PIXI.PixiShader = function() +{ + /** + * @property {any} program - The WebGL program. + */ + this.program; + + /** + * @property {array} fragmentSrc - The fragment shader. + */ + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + + /** + * @property {number} textureCount - A local texture counter for multi-texture shaders. + */ + this.textureCount = 0; + +} + +/** +* @method PIXI.PixiShader#init +*/ +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +/** +* Updates the shader uniform values. +* Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/ +* http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf +* +* @method PIXI.PixiShader#syncUniforms +*/ +PIXI.PixiShader.prototype.syncUniforms = function() +{ + this.textureCount = 1; + + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + var type = this.uniforms[key].type; + var transpose = false; + + if (this.uniforms[key].transpose) + { + transpose = this.uniforms[key].transpose; + } + + if (type == "1f") + { + // void uniform1f(WebGLUniformLocation? location, GLfloat x); + gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1fv") + { + // void uniform1fv(WebGLUniformLocation? location, Float32Array v); + // void uniform1fv(WebGLUniformLocation? location, sequence v); + gl.uniform1fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1i") + { + // void uniform1i(WebGLUniformLocation? location, GLint x); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1iv") + { + // void uniform1iv(WebGLUniformLocation? location, Int32Array v); + // void uniform1iv(WebGLUniformLocation? location, sequence v); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2f") + { + // void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y); + gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2fv") + { + // void uniform2fv(WebGLUniformLocation? location, Float32Array v); + // void uniform2fv(WebGLUniformLocation? location, sequence v); + gl.uniform2fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2i") + { + // void uniform2i(WebGLUniformLocation? location, GLint x, GLint y); + gl.uniform2i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2iv") + { + // void uniform2iv(WebGLUniformLocation? location, Int32Array v); + // void uniform2iv(WebGLUniformLocation? location, sequence v); + gl.uniform2iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3f") + { + // void uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z); + gl.uniform3f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3fv") + { + // void uniform3fv(WebGLUniformLocation? location, Float32Array v); + // void uniform3fv(WebGLUniformLocation? location, sequence v); + gl.uniform3fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3i") + { + // void uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z); + gl.uniform3i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3iv") + { + // void uniform3iv(WebGLUniformLocation? location, Int32Array v); + // void uniform3iv(WebGLUniformLocation? location, sequence v); + gl.uniform3iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4f") + { + // void uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + gl.uniform4f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4fv") + { + // void uniform4fv(WebGLUniformLocation? location, Float32Array v); + // void uniform4fv(WebGLUniformLocation? location, sequence v); + gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4i") + { + // void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w); + gl.uniform4i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4iv") + { + // void uniform4iv(WebGLUniformLocation? location, Int32Array v); + // void uniform4iv(WebGLUniformLocation? location, sequence v); + gl.uniform4iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "mat2") + { + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix2fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat3") + { + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix3fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat4") + { + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "sampler2D") + { + if (this.uniforms[key].value.baseTexture.hasLoaded) + { + var texture = this.uniforms[key].value.baseTexture._glTexture; + var image = this.uniforms[key].value.baseTexture.source; + var format = gl.RGBA; + + if (this.uniforms[key].format && this.uniforms[key].format == 'luminance') + { + format = gl.LUMINANCE; + } + + gl.activeTexture(gl['TEXTURE' + this.textureCount]); + + if (this.uniforms[key].wrap) + { + if (this.uniforms[key].wrap == 'no-repeat' || this.uniforms[key].wrap === false) + { + this.createGLTextureLinear(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'repeat' || this.uniforms[key].wrap === true) + { + this.createGLTexture(gl, image, format, texture); + } + else if (this.uniforms[key].wrap == 'nearest-repeat') + { + this.createGLTextureNearestRepeat(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'nearest') + { + this.createGLTextureNearest(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'audio') + { + this.createAudioTexture(gl, texture); + } + else if (this.uniforms[key].wrap == 'keyboard') + { + this.createKeyboardTexture(gl, texture); + } + } + else + { + this.createGLTextureLinear(gl, image, texture); + } + + gl.uniform1i(this.uniforms[key].uniformLocation, this.textureCount); + + this.textureCount++; + } + } + } + +}; + +/** +* Binds the given texture and image data. The texture is set to REPEAT. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTexture +*/ +PIXI.PixiShader.prototype.createGLTexture = function(gl, image, format, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.generateMipmap(gl.TEXTURE_2D); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureLinear +*/ +PIXI.PixiShader.prototype.createGLTextureLinear = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture and image data. The texture is set to REPEAT with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearestRepeat +*/ +PIXI.PixiShader.prototype.createGLTextureNearestRepeat = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearest +*/ +PIXI.PixiShader.prototype.createGLTextureNearest = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with real-time audio data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createAudioTexture +*/ +PIXI.PixiShader.prototype.createAudioTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 512, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with keyboard input data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createKeyboardTexture +*/ +PIXI.PixiShader.prototype.createKeyboardTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 256, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +PIXI.PixiShader.defaultVertexSrc = [ + + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "varying vec2 vTextureCoord;", + + "varying float vColor;", + + "const vec2 center = vec2(-1.0, 1.0);", + + "void main(void) {", + "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" +]; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.StripShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float alpha;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", + "gl_FragColor = gl_FragColor * alpha;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "varying vec2 vTextureCoord;", + "varying vec2 offsetVector;", + "varying float vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" + ]; +} + +PIXI.StripShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PrimitiveShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec4 vColor;", + "void main(void) {", + "gl_FragColor = vColor;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec4 aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "uniform float alpha;", + "varying vec4 vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vColor = aColor * alpha;", + "}" + ]; + +} + +PIXI.PrimitiveShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A set of functions used by the webGL renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.WebGLGraphics = function() +{ + +} + +/** + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param projection {Object} + */ +PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) +{ + var gl = PIXI.gl; + + if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, + buffer:gl.createBuffer(), + indexBuffer:gl.createBuffer()}; + + if(graphics.dirty) + { + graphics.dirty = false; + + if(graphics.clearDirty) + { + graphics.clearDirty = false; + + graphics._webGL.lastIndex = 0; + graphics._webGL.points = []; + graphics._webGL.indices = []; + + } + + PIXI.WebGLGraphics.updateGraphics(graphics); + } + + PIXI.activatePrimitiveShader(); + + // This could be speeded up fo sure! + var m = PIXI.mat3.clone(graphics.worldTransform); + + PIXI.mat3.transpose(m); + + // set the matrix transform for the + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); + + gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); + gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + + gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); + gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); + + // set the index buffer! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + + + gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + + PIXI.deactivatePrimitiveShader(); + + + // return to default shader... +// PIXI.activateShader(PIXI.defaultShader); +} + +/** + * Updates the graphics object + * + * @static + * @private + * @method updateGraphics + * @param graphics {Graphics} + */ +PIXI.WebGLGraphics.updateGraphics = function(graphics) +{ + for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + + if(data.type == PIXI.Graphics.POLY) + { + if(data.fill) + { + if(data.points.length>3) + PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); + } + + if(data.lineWidth > 0) + { + PIXI.WebGLGraphics.buildLine(data, graphics._webGL); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); + } + else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) + { + PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); + } + }; + + graphics._webGL.lastIndex = graphics.graphicsData.length; + + var gl = PIXI.gl; + + graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); + + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); + + graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); +} + +/** + * Builds a rectangle to draw + * + * @static + * @private + * @method buildRectangle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vertPos = verts.length/6; + + // start + verts.push(x, y); + verts.push(r, g, b, alpha); + + verts.push(x + width, y); + verts.push(r, g, b, alpha); + + verts.push(x , y + height); + verts.push(r, g, b, alpha); + + verts.push(x + width, y + height); + verts.push(r, g, b, alpha); + + // insert 2 dead triangles.. + indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) + } + + if(graphicsData.lineWidth) + { + graphicsData.points = [x, y, + x + width, y, + x + width, y + height, + x, y + height, + x, y]; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a circle to draw + * + * @static + * @private + * @method buildCircle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + var totalSegs = 40; + var seg = (Math.PI * 2) / totalSegs ; + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vecPos = verts.length/6; + + indices.push(vecPos); + + for (var i=0; i < totalSegs + 1 ; i++) + { + verts.push(x,y, r, g, b, alpha); + + verts.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height, + r, g, b, alpha); + + indices.push(vecPos++, vecPos++); + }; + + indices.push(vecPos-1); + } + + if(graphicsData.lineWidth) + { + graphicsData.points = []; + + for (var i=0; i < totalSegs + 1; i++) + { + graphicsData.points.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height) + }; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a line to draw + * + * @static + * @private + * @method buildLine + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) +{ + // TODO OPTIMISE! + + var wrap = true; + var points = graphicsData.points; + if(points.length == 0)return; + + // if the line width is an odd number add 0.5 to align to a whole pixel + if(graphicsData.lineWidth%2) + { + for (var i = 0; i < points.length; i++) { + points[i] += 0.5; + }; + } + + // get first and last point.. figure out the middle! + var firstPoint = new PIXI.Point( points[0], points[1] ); + var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + // if the first point is the last point - goona have issues :) + if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) + { + points.pop(); + points.pop(); + + lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; + var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; + + points.unshift(midPointX, midPointY); + points.push(midPointX, midPointY) + } + + var verts = webGLData.points; + var indices = webGLData.indices; + var length = points.length / 2; + var indexCount = points.length; + var indexStart = verts.length/6; + + // DRAW the Line + var width = graphicsData.lineWidth / 2; + + // sort color + var color = HEXtoRGB(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var p1x, p1y, p2x, p2y, p3x, p3y; + var perpx, perpy, perp2x, perp2y, perp3x, perp3y; + var ipx, ipy; + var a1, b1, c1, a2, b2, c2; + var denom, pdist, dist; + + p1x = points[0]; + p1y = points[1]; + + p2x = points[2]; + p2y = points[3]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + // start + verts.push(p1x - perpx , p1y - perpy, + r, g, b, alpha); + + verts.push(p1x + perpx , p1y + perpy, + r, g, b, alpha); + + for (var i = 1; i < length-1; i++) + { + p1x = points[(i-1)*2]; + p1y = points[(i-1)*2 + 1]; + + p2x = points[(i)*2] + p2y = points[(i)*2 + 1] + + p3x = points[(i+1)*2]; + p3y = points[(i+1)*2 + 1]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + perp2x = -(p2y - p3y); + perp2y = p2x - p3x; + + dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); + perp2x /= dist; + perp2y /= dist; + perp2x *= width; + perp2y *= width; + + a1 = (-perpy + p1y) - (-perpy + p2y); + b1 = (-perpx + p2x) - (-perpx + p1x); + c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); + a2 = (-perp2y + p3y) - (-perp2y + p2y); + b2 = (-perp2x + p2x) - (-perp2x + p3x); + c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); + + denom = a1*b2 - a2*b1; + + if(Math.abs(denom) < 0.1 ) + { + + denom+=10.1; + verts.push(p2x - perpx , p2y - perpy, + r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy, + r, g, b, alpha); + + continue; + } + + px = (b1*c2 - b2*c1)/denom; + py = (a2*c1 - a1*c2)/denom; + + + pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); + + + if(pdist > 140 * 140) + { + perp3x = perpx - perp2x; + perp3y = perpy - perp2y; + + dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); + perp3x /= dist; + perp3y /= dist; + perp3x *= width; + perp3y *= width; + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x + perp3x, p2y +perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + indexCount++; + } + else + { + + verts.push(px , py); + verts.push(r, g, b, alpha); + + verts.push(p2x - (px-p2x), p2y - (py - p2y)); + verts.push(r, g, b, alpha); + } + } + + p1x = points[(length-2)*2] + p1y = points[(length-2)*2 + 1] + + p2x = points[(length-1)*2] + p2y = points[(length-1)*2 + 1] + + perpx = -(p1y - p2y) + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + verts.push(p2x - perpx , p2y - perpy) + verts.push(r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy) + verts.push(r, g, b, alpha); + + indices.push(indexStart); + + for (var i=0; i < indexCount; i++) + { + indices.push(indexStart++); + }; + + indices.push(indexStart-1); +} + +/** + * Builds a polygon to draw + * + * @static + * @private + * @method buildPoly + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) +{ + var points = graphicsData.points; + if(points.length < 6)return; + + // get first and last point.. figure out the middle! + var verts = webGLData.points; + var indices = webGLData.indices; + + var length = points.length / 2; + + // sort color + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var triangles = PIXI.PolyK.Triangulate(points); + + var vertPos = verts.length / 6; + + for (var i=0; i < triangles.length; i+=3) + { + indices.push(triangles[i] + vertPos); + indices.push(triangles[i] + vertPos); + indices.push(triangles[i+1] + vertPos); + indices.push(triangles[i+2] +vertPos); + indices.push(triangles[i+2] + vertPos); + }; + + for (var i = 0; i < length; i++) + { + verts.push(points[i * 2], points[i * 2 + 1], + r, g, b, alpha); + }; +} + +function HEXtoRGB(hex) { + return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); + +// an instance of the gl context.. +// only one at the moment :/ +PIXI.gl; + +/** + * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer + * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. + * So no need for Sprite Batch's or Sprite Cloud's + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class WebGLRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) + * + */ +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) +{ + // do a catch.. only 1 webGL renderer.. + + this.transparent = !!transparent; + + this.width = width || 800; + this.height = height || 600; + + this.view = view || document.createElement( 'canvas' ); + this.view.width = this.width; + this.view.height = this.height; + + // deal with losing context.. + var scope = this; + this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) + this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) + + this.batchs = []; + + var options = { + alpha: this.transparent, + antialias:!!antialias, // SPEED UP?? + premultipliedAlpha:false, + stencil:true + } + + //try 'experimental-webgl' + try { + PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); + } catch (e) { + //try 'webgl' + try { + PIXI.gl = this.gl = this.view.getContext("webgl", options); + } catch (e) { + // fail, not able to get a context + throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); + } + } + + PIXI.initDefaultShaders(); + + + + + // PIXI.activateDefaultShader(); + + var gl = this.gl; + + gl.useProgram(PIXI.defaultShader.program); + + + PIXI.WebGLRenderer.gl = gl; + + this.batch = new PIXI.WebGLBatch(gl); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, this.transparent); + + PIXI.projection = new PIXI.Point(400, 300); + PIXI.offset = new PIXI.Point(0, 0); + + // TODO remove thease globals.. + + this.resize(this.width, this.height); + this.contextLost = false; + + //PIXI.pushShader(PIXI.defaultShader); + + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); + // this.stageRenderGroup. = this.transparent +} + +// constructor +PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; + +/** + * Gets a new WebGLBatch from the pool + * + * @static + * @method getBatch + * @return {WebGLBatch} + * @private + */ +PIXI.WebGLRenderer.getBatch = function() +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * Puts a batch back into the pool + * + * @static + * @method returnBatch + * @param batch {WebGLBatch} The batch to return + * @private + */ +PIXI.WebGLRenderer.returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * Renders the stage to its webGL view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.WebGLRenderer.prototype.render = function(stage) +{ + if(this.contextLost)return; + + + // if rendering a new stage clear the batchs.. + if(this.__stage !== stage) + { + // TODO make this work + // dont think this is needed any more? + this.__stage = stage; + this.stageRenderGroup.setRenderable(stage); + } + + // update any textures + PIXI.WebGLRenderer.updateTextures(); + + // update the scene graph + PIXI.visibleCount++; + stage.updateTransform(); + + var gl = this.gl; + + // -- Does this need to be set every frame? -- // + gl.colorMask(true, true, true, this.transparent); + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + gl.clear(gl.COLOR_BUFFER_BIT); + + // HACK TO TEST + + this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + this.stageRenderGroup.render(PIXI.projection); + + // interaction + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // after rendering lets confirm all frames that have been uodated.. + if(PIXI.Texture.frameUpdates.length > 0) + { + for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) + { + PIXI.Texture.frameUpdates[i].updateFrame = false; + }; + + PIXI.Texture.frameUpdates = []; + } +} + +/** + * Updates the textures loaded into this webgl renderer + * + * @static + * @method updateTextures + * @private + */ +PIXI.WebGLRenderer.updateTextures = function() +{ + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; +} + +/** + * Updates a loaded webgl texture + * + * @static + * @method updateTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.updateTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(!texture._glTexture) + { + texture._glTexture = gl.createTexture(); + } + + if(texture.hasLoaded) + { + gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + + // reguler... + + if(!texture._powerOf2) + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + } +} + +/** + * Destroys a loaded webgl texture + * + * @method destroyTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.destroyTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(texture._glTexture) + { + texture._glTexture = gl.createTexture(); + gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + } +} + +/** + * resizes the webGL view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the webGL view + * @param height {Number} the new height of the webGL view + */ +PIXI.WebGLRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; + + this.gl.viewport(0, 0, this.width, this.height); + + //var projectionMatrix = this.projectionMatrix; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + //PIXI.size.x = this.width/2; + //PIXI.size.y = -this.height/2; + +// projectionMatrix[0] = 2/this.width; +// projectionMatrix[5] = -2/this.height; +// projectionMatrix[12] = -1; +// projectionMatrix[13] = 1; +} + +/** + * Handles a lost webgl context + * + * @method handleContextLost + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextLost = function(event) +{ + event.preventDefault(); + this.contextLost = true; +} + +/** + * Handles a restored webgl context + * + * @method handleContextRestored + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) +{ + this.gl = this.view.getContext("experimental-webgl", { + alpha: true + }); + + this.initShaders(); + + for(var key in PIXI.TextureCache) + { + var texture = PIXI.TextureCache[key].baseTexture; + texture._glTexture = null; + PIXI.WebGLRenderer.updateTexture(texture); + }; + + for (var i=0; i < this.batchs.length; i++) + { + this.batchs[i].restoreLostContext(this.gl)// + this.batchs[i].dirty = true; + }; + + PIXI._restoreBatchs(this.gl); + + this.contextLost = false; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._batchs = []; + +/** + * @private + */ +PIXI._getBatch = function(gl) +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * @private + */ +PIXI._returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * @private + */ +PIXI._restoreBatchs = function(gl) +{ + for (var i=0; i < PIXI._batchs.length; i++) + { + PIXI._batchs[i].restoreLostContext(gl); + }; +} + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. + * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites + * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled + * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @constructor + * @param gl {WebGLContext} an instance of the webGL context + */ +PIXI.WebGLBatch = function(gl) +{ + this.gl = gl; + + this.size = 0; + + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); + this.blendMode = PIXI.blendModes.NORMAL; + this.dynamicSize = 1; +} + +// constructor +PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; + +/** + * Cleans the batch so that is can be returned to an object pool and reused + * + * @method clean + */ +PIXI.WebGLBatch.prototype.clean = function() +{ + this.verticies = []; + this.uvs = []; + this.indices = []; + this.colors = []; + this.dynamicSize = 1; + this.texture = null; + this.last = null; + this.size = 0; + this.head; + this.tail; +} + +/** + * Recreates the buffers in the event of a context loss + * + * @method restoreLostContext + * @param gl {WebGLContext} + */ +PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) +{ + this.gl = gl; + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); +} + +/** + * inits the batch's texture and blend mode based if the supplied sprite + * + * @method init + * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with + * the same base texture and blend mode will be allowed to be added to this batch + */ +PIXI.WebGLBatch.prototype.init = function(sprite) +{ + sprite.batch = this; + this.dirty = true; + this.blendMode = sprite.blendMode; + this.texture = sprite.texture.baseTexture; + this.head = sprite; + this.tail = sprite; + this.size = 1; + + this.growBatch(); +} + +/** + * inserts a sprite before the specified sprite + * + * @method insertBefore + * @param sprite {Sprite} the sprite to be added + * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite + */ +PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + var tempPrev = nextSprite.__prev; + nextSprite.__prev = sprite; + sprite.__next = nextSprite; + + if(tempPrev) + { + sprite.__prev = tempPrev; + tempPrev.__next = sprite; + } + else + { + this.head = sprite; + } +} + +/** + * inserts a sprite after the specified sprite + * + * @method insertAfter + * @param sprite {Sprite} the sprite to be added + * @param previousSprite {Sprite} the first sprite will be inserted after this sprite + */ +PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + + var tempNext = previousSprite.__next; + previousSprite.__next = sprite; + sprite.__prev = previousSprite; + + if(tempNext) + { + sprite.__next = tempNext; + tempNext.__prev = sprite; + } + else + { + this.tail = sprite + } +} + +/** + * removes a sprite from the batch + * + * @method remove + * @param sprite {Sprite} the sprite to be removed + */ +PIXI.WebGLBatch.prototype.remove = function(sprite) +{ + this.size--; + + if(this.size == 0) + { + sprite.batch = null; + sprite.__prev = null; + sprite.__next = null; + return; + } + + if(sprite.__prev) + { + sprite.__prev.__next = sprite.__next; + } + else + { + this.head = sprite.__next; + this.head.__prev = null; + } + + if(sprite.__next) + { + sprite.__next.__prev = sprite.__prev; + } + else + { + this.tail = sprite.__prev; + this.tail.__next = null + } + + sprite.batch = null; + sprite.__next = null; + sprite.__prev = null; + this.dirty = true; +} + +/** + * Splits the batch into two with the specified sprite being the start of the new batch. + * + * @method split + * @param sprite {Sprite} the sprite that indicates where the batch should be split + * @return {WebGLBatch} the new batch + */ +PIXI.WebGLBatch.prototype.split = function(sprite) +{ + this.dirty = true; + + var batch = new PIXI.WebGLBatch(this.gl); + batch.init(sprite); + batch.texture = this.texture; + batch.tail = this.tail; + + this.tail = sprite.__prev; + this.tail.__next = null; + + sprite.__prev = null; + // return a splite batch! + + // TODO this size is wrong! + // need to recalculate :/ problem with a linked list! + // unless it gets calculated in the "clean"? + + // need to loop through items as there is no way to know the length on a linked list :/ + var tempSize = 0; + while(sprite) + { + tempSize++; + sprite.batch = batch; + sprite = sprite.__next; + } + + batch.size = tempSize; + this.size -= tempSize; + + return batch; +} + +/** + * Merges two batchs together + * + * @method merge + * @param batch {WebGLBatch} the batch that will be merged + */ +PIXI.WebGLBatch.prototype.merge = function(batch) +{ + this.dirty = true; + + this.tail.__next = batch.head; + batch.head.__prev = this.tail; + + this.size += batch.size; + + this.tail = batch.tail; + + var sprite = batch.head; + while(sprite) + { + sprite.batch = this; + sprite = sprite.__next; + } +} + +/** + * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this + * function is used to increase the size of the batch. It also creates a little extra room so + * that the batch does not need to be resized every time a sprite is added + * + * @method growBatch + */ +PIXI.WebGLBatch.prototype.growBatch = function() +{ + var gl = this.gl; + if( this.size == 1) + { + this.dynamicSize = 1; + } + else + { + this.dynamicSize = this.size * 1.5 + } + // grow verts + this.verticies = new Float32Array(this.dynamicSize * 8); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); + + this.uvs = new Float32Array( this.dynamicSize * 8 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); + + this.dirtyUVS = true; + + this.colors = new Float32Array( this.dynamicSize * 4 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); + + this.dirtyColors = true; + + this.indices = new Uint16Array(this.dynamicSize * 6); + var length = this.indices.length/6; + + for (var i=0; i < length; i++) + { + var index2 = i * 6; + var index3 = i * 4; + this.indices[index2 + 0] = index3 + 0; + this.indices[index2 + 1] = index3 + 1; + this.indices[index2 + 2] = index3 + 2; + this.indices[index2 + 3] = index3 + 0; + this.indices[index2 + 4] = index3 + 2; + this.indices[index2 + 5] = index3 + 3; + }; + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); +} + +/** + * Refresh's all the data in the batch and sync's it with the webGL buffers + * + * @method refresh + */ +PIXI.WebGLBatch.prototype.refresh = function() +{ + var gl = this.gl; + + if (this.dynamicSize < this.size) + { + this.growBatch(); + } + + var indexRun = 0; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; + var a, b, c, d, tx, ty; + + var displayObject = this.head; + + while(displayObject) + { + index = indexRun * 8; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + + colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + + displayObject = displayObject.__next; + + indexRun ++; + } + + this.dirtyUVS = true; + this.dirtyColors = true; +} + +/** + * Updates all the relevant geometry and uploads the data to the GPU + * + * @method update + */ +PIXI.WebGLBatch.prototype.update = function() +{ + var gl = this.gl; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 + + var a, b, c, d, tx, ty; + + var indexRun = 0; + + var displayObject = this.head; + var verticies = this.verticies; + var uvs = this.uvs; + var colors = this.colors; + + while(displayObject) + { + if(displayObject.vcount === PIXI.visibleCount) + { + width = displayObject.texture.frame.width; + height = displayObject.texture.frame.height; + + // TODO trim?? + aX = displayObject.anchor.x;// - displayObject.texture.trim.x + aY = displayObject.anchor.y; //- displayObject.texture.trim.y + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + index = indexRun * 8; + + worldTransform = displayObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + verticies[index + 0 ] = a * w1 + c * h1 + tx; + verticies[index + 1 ] = d * h1 + b * w1 + ty; + + verticies[index + 2 ] = a * w0 + c * h1 + tx; + verticies[index + 3 ] = d * h1 + b * w0 + ty; + + verticies[index + 4 ] = a * w0 + c * h0 + tx; + verticies[index + 5 ] = d * h0 + b * w0 + ty; + + verticies[index + 6] = a * w1 + c * h0 + tx; + verticies[index + 7] = d * h0 + b * w1 + ty; + + if(displayObject.updateFrame || displayObject.texture.updateFrame) + { + this.dirtyUVS = true; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + uvs[index + 0] = frame.x / tw; + uvs[index +1] = frame.y / th; + + uvs[index +2] = (frame.x + frame.width) / tw; + uvs[index +3] = frame.y / th; + + uvs[index +4] = (frame.x + frame.width) / tw; + uvs[index +5] = (frame.y + frame.height) / th; + + uvs[index +6] = frame.x / tw; + uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + } + + // TODO this probably could do with some optimisation.... + if(displayObject.cacheAlpha != displayObject.worldAlpha) + { + displayObject.cacheAlpha = displayObject.worldAlpha; + + var colorIndex = indexRun * 4; + colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; + this.dirtyColors = true; + } + } + else + { + index = indexRun * 8; + + verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; + } + + indexRun++; + displayObject = displayObject.__next; + } +} + +/** + * Draws the batch to the frame buffer + * + * @method render + */ +PIXI.WebGLBatch.prototype.render = function(start, end) +{ + start = start || 0; + + if(end == undefined)end = this.size; + + if(this.dirty) + { + this.refresh(); + this.dirty = false; + } + + if (this.size == 0)return; + + this.update(); + var gl = this.gl; + + //TODO optimize this! + + var shaderProgram = PIXI.defaultShader; + + //gl.useProgram(shaderProgram); + + // update the verts.. + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + // ok.. + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) + gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + // update the uvs + //var isDefault = (shaderProgram == PIXI.shaderProgram) + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + if(this.dirtyUVS) + { + this.dirtyUVS = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); + } + + gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); + + // update color! + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + + if(this.dirtyColors) + { + this.dirtyColors = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); + } + + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + var len = end - start; + + // DRAW THAT this! + gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be + * grouped into a batch. All the sprites in a batch can then be drawn in one go by the + * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch + * even if the batch only contains one sprite. Batching is handled automatically by the + * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @contructor + * @param gl {WebGLContext} An instance of the webGL context + */ +PIXI.WebGLRenderGroup = function(gl, transparent) +{ + this.gl = gl; + this.root; + + this.backgroundColor; + this.transparent = transparent == undefined ? true : transparent; + + this.batchs = []; + this.toRemove = []; + console.log(this.transparent) + this.filterManager = new PIXI.WebGLFilterManager(this.transparent); +} + +// constructor +PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; + +/** + * Add a display object to the webgl renderer + * + * @method setRenderable + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) +{ + // has this changed?? + if(this.root)this.removeDisplayObjectAndChildren(this.root); + + displayObject.worldVisible = displayObject.visible; + + // soooooo // + // to check if any batchs exist already?? + + // TODO what if its already has an object? should remove it + this.root = displayObject; + this.addDisplayObjectAndChildren(displayObject); +} + +/** + * Renders the stage to its webgl view + * + * @method render + * @param projection {Object} + */ +PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + + var gl = this.gl; + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + // will render all the elements in the group + var renderable; + + for (var i=0; i < this.batchs.length; i++) + { + + renderable = this.batchs[i]; + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + continue; + } + + // render special + this.renderSpecial(renderable, projection); + } + +} + +/** + * Renders a specific displayObject + * + * @method renderSpecific + * @param displayObject {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + var gl = this.gl; + + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + // to do! + // render part of the scene... + + var startIndex; + var startBatchIndex; + + var endIndex; + var endBatchIndex; + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.first; + while(nextRenderable._iNext) + { + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + nextRenderable = nextRenderable._iNext; + } + var startBatch = nextRenderable.batch; + //console.log(nextRenderable); + + //console.log(renderable) + if(nextRenderable instanceof PIXI.Sprite) + { + startBatch = nextRenderable.batch; + + var head = startBatch.head; + var next = head; + + // ok now we have the batch.. need to find the start index! + if(head == nextRenderable) + { + startIndex = 0; + } + else + { + startIndex = 1; + + while(head.__next != nextRenderable) + { + startIndex++; + head = head.__next; + } + } + } + else + { + startBatch = nextRenderable; + } + + // Get the LAST renderable object + var lastRenderable = displayObject.last; + while(lastRenderable._iPrev) + { + if(lastRenderable.renderable && lastRenderable.__renderGroup)break; + lastRenderable = lastRenderable._iNext; + } + + if(lastRenderable instanceof PIXI.Sprite) + { + endBatch = lastRenderable.batch; + + var head = endBatch.head; + + if(head == lastRenderable) + { + endIndex = 0; + } + else + { + endIndex = 1; + + while(head.__next != lastRenderable) + { + endIndex++; + head = head.__next; + } + } + } + else + { + endBatch = lastRenderable; + } + + //console.log(endBatch); + // TODO - need to fold this up a bit! + + if(startBatch == endBatch) + { + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex, endIndex+1); + } + else + { + this.renderSpecial(startBatch, projection); + } + return; + } + + // now we have first and last! + startBatchIndex = this.batchs.indexOf(startBatch); + endBatchIndex = this.batchs.indexOf(endBatch); + + // DO the first batch + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex); + } + else + { + this.renderSpecial(startBatch, projection); + } + + // DO the middle batchs.. + for (var i=startBatchIndex+1; i < endBatchIndex; i++) + { + renderable = this.batchs[i]; + + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + } + else + { + this.renderSpecial(renderable, projection); + } + } + + // DO the last batch.. + if(endBatch instanceof PIXI.WebGLBatch) + { + endBatch.render(0, endIndex+1); + } + else + { + this.renderSpecial(endBatch, projection); + } +} + +/** + * Renders a specific renderable + * + * @method renderSpecial + * @param renderable {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) +{ + + var worldVisible = renderable.vcount === PIXI.visibleCount + + + if(renderable instanceof PIXI.TilingSprite) + { + if(worldVisible)this.renderTilingSprite(renderable, projection); + } + else if(renderable instanceof PIXI.Strip) + { + if(worldVisible)this.renderStrip(renderable, projection); + } + else if(renderable instanceof PIXI.CustomRenderable) + { + if(worldVisible) renderable.renderWebGL(this, projection); + } + else if(renderable instanceof PIXI.Graphics) + { + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + } + else if(renderable instanceof PIXI.FilterBlock) + { + this.handleFilterBlock(renderable, projection); + } +} + +flip = false; +var maskStack = []; +var maskPosition = 0; + +//var usedMaskStack = []; + +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; + + if(filterBlock.open) + { + if(filterBlock.data instanceof Array) + { + this.filterManager.pushFilter(filterBlock); + // ok so.. + + } + else + { + maskPosition++; + + maskStack.push(filterBlock) + + gl.enable(gl.STENCIL_TEST); + + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); + + PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + } + } + else + { + if(filterBlock.data instanceof Array) + { + this.filterManager.popFilter(); + } + else + { + var maskData = maskStack.pop(filterBlock) + + + if(maskData) + { + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); + + PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + }; + + gl.disable(gl.STENCIL_TEST); + } + } +} + +/** + * Updates a webgl texture + * + * @method updateTexture + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) +{ + + // TODO definitely can optimse this function.. + + this.removeObject(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = displayObject.first; + while(previousRenderable != this.root) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + this.insertObject(displayObject, previousRenderable, nextRenderable); +} + +/** + * Adds filter blocks + * + * @method addFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) +{ + start.__renderGroup = this; + end.__renderGroup = this; + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = start; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + this.insertAfter(start, previousRenderable); + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var previousRenderable2 = end; + while(previousRenderable2 != this.root.first) + { + previousRenderable2 = previousRenderable2._iPrev; + if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; + } + this.insertAfter(end, previousRenderable2); +} + +/** + * Remove filter blocks + * + * @method removeFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) +{ + this.removeObject(start); + this.removeObject(end); +} + +/** + * Adds a display object and children to the webgl context + * + * @method addDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + + var previousRenderable = displayObject.first; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + // one the display object hits this. we can break the loop + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + do + { + tempObject.__renderGroup = this; + + if(tempObject.renderable) + { + + this.insertObject(tempObject, previousRenderable, nextRenderable); + previousRenderable = tempObject; + } + + tempObject = tempObject._iNext; + } + while(tempObject != testObject) +} + +/** + * Removes a display object and children to the webgl context + * + * @method removeDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup != this)return; + +// var displayObject = displayObject.first; + var lastObject = displayObject.last; + do + { + displayObject.__renderGroup = null; + if(displayObject.renderable)this.removeObject(displayObject); + displayObject = displayObject._iNext; + } + while(displayObject) +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertObject + * @param displayObject {DisplayObject} + * @param previousObject {DisplayObject} + * @param nextObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) +{ + // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED + var previousSprite = previousObject; + var nextSprite = nextObject; + + /* + * so now we have the next renderable and the previous renderable + * + */ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch + var nextBatch + + if(previousSprite instanceof PIXI.Sprite) + { + previousBatch = previousSprite.batch; + if(previousBatch) + { + if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) + { + previousBatch.insertAfter(displayObject, previousSprite); + return; + } + } + } + else + { + // TODO reword! + previousBatch = previousSprite; + } + + if(nextSprite) + { + if(nextSprite instanceof PIXI.Sprite) + { + nextBatch = nextSprite.batch; + + //batch may not exist if item was added to the display list but not to the webGL + if(nextBatch) + { + if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) + { + nextBatch.insertBefore(displayObject, nextSprite); + return; + } + else + { + if(nextBatch == previousBatch) + { + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(nextSprite); + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var batch = PIXI.WebGLRenderer.getBatch(); + + var index = this.batchs.indexOf( previousBatch ); + batch.init(displayObject); + this.batchs.splice(index+1, 0, batch, splitBatch); + + return; + } + } + } + } + else + { + // TODO re-word! + + nextBatch = nextSprite; + } + } + + /* + * looks like it does not belong to any batch! + * but is also not intersecting one.. + * time to create anew one! + */ + + var batch = PIXI.WebGLRenderer.getBatch(); + batch.init(displayObject); + + if(previousBatch) // if this is invalid it means + { + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, batch); + } + else + { + this.batchs.push(batch); + } + + return; + } + else if(displayObject instanceof PIXI.TilingSprite) + { + + // add to a batch!! + this.initTilingSprite(displayObject); + // this.batchs.push(displayObject); + + } + else if(displayObject instanceof PIXI.Strip) + { + // add to a batch!! + this.initStrip(displayObject); + // this.batchs.push(displayObject); + } + else if(displayObject)// instanceof PIXI.Graphics) + { + //displayObject.initWebGL(this); + + // add to a batch!! + //this.initStrip(displayObject); + //this.batchs.push(displayObject); + } + + this.insertAfter(displayObject, previousSprite); + + // insert and SPLIT! + +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertAfter + * @param item {DisplayObject} + * @param displayObject {DisplayObject} The object to insert + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) +{ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch = displayObject.batch; + + if(previousBatch) + { + // so this object is in a batch! + + // is it not? need to split the batch + if(previousBatch.tail == displayObject) + { + // is it tail? insert in to batchs + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item); + } + else + { + // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // + + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(displayObject.__next); + + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item, splitBatch); + } + } + else + { + this.batchs.push(item); + } + } + else + { + var index = this.batchs.indexOf( displayObject ); + this.batchs.splice(index+1, 0, item); + } +} + +/** + * Removes a displayObject from the linked list + * + * @method removeObject + * @param displayObject {DisplayObject} The object to remove + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) +{ + // loop through children.. + // display object // + + // add a child from the render group.. + // remove it and all its children! + //displayObject.cacheVisible = false;//displayObject.visible; + + /* + * removing is a lot quicker.. + * + */ + var batchToRemove; + + if(displayObject instanceof PIXI.Sprite) + { + // should always have a batch! + var batch = displayObject.batch; + if(!batch)return; // this means the display list has been altered befre rendering + + batch.remove(displayObject); + + if(batch.size==0) + { + batchToRemove = batch; + } + } + else + { + batchToRemove = displayObject; + } + + /* + * Looks like there is somthing that needs removing! + */ + if(batchToRemove) + { + var index = this.batchs.indexOf( batchToRemove ); + if(index == -1)return;// this means it was added then removed before rendered + + // ok so.. check to see if you adjacent batchs should be joined. + // TODO may optimise? + if(index == 0 || index == this.batchs.length-1) + { + // wha - eva! just get of the empty batch! + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + + return; + } + + if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) + { + if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) + { + //console.log("MERGE") + this.batchs[index-1].merge(this.batchs[index+1]); + + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); + this.batchs.splice(index, 2); + return; + } + } + + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + } +} + + +/** + * Initializes a tiling sprite + * + * @method initTilingSprite + * @param sprite {TilingSprite} The tiling sprite to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) +{ + var gl = this.gl; + + // make the texture tilable.. + + sprite.verticies = new Float32Array([0, 0, + sprite.width, 0, + sprite.width, sprite.height, + 0, sprite.height]); + + sprite.uvs = new Float32Array([0, 0, + 1, 0, + 1, 1, + 0, 1]); + + sprite.colors = new Float32Array([1,1,1,1]); + + sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); + + sprite._vertexBuffer = gl.createBuffer(); + sprite._indexBuffer = gl.createBuffer(); + sprite._uvBuffer = gl.createBuffer(); + sprite._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); + +// return ( (x > 0) && ((x & (x - 1)) == 0) ); + + if(sprite.texture.baseTexture._glTexture) + { + gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + sprite.texture.baseTexture._powerOf2 = true; + } + else + { + sprite.texture.baseTexture._powerOf2 = true; + } +} + +/** + * Renders a Strip + * + * @method renderStrip + * @param strip {Strip} The strip to render + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) +{ + var gl = this.gl; + + PIXI.activateStripShader(); + + var shader = PIXI.stripShader; + + var program = shader.program; + + var m = PIXI.mat3.clone(strip.worldTransform); + + PIXI.mat3.transpose(m); + +// console.log(projection) + // set the matrix transform for the + gl.uniformMatrix3fv(shader.translationMatrix, false, m); + gl.uniform2f(shader.projectionVector, projection.x, projection.y); + gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(shader.alpha, strip.worldAlpha); + + /* + if(strip.blendMode == PIXI.blendModes.NORMAL) + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); + } + */ + + //console.log("!!") + if(!strip.dirty) + { + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + } + else + { + strip.dirty = false; + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + // console.log(strip.texture.baseTexture._glTexture) + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); + + } + + gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); + + PIXI.deactivateStripShader(); + //gl.useProgram(PIXI.currentProgram); +} + +/** + * Renders a TilingSprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tiling sprite to render + * @param projectionMatrix {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) +{ + var gl = this.gl; + + + var shaderProgram = PIXI.shaderProgram; + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + var offsetX = tilePosition.x/sprite.texture.baseTexture.width; + var offsetY = tilePosition.y/sprite.texture.baseTexture.height; + + var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; + var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; + + sprite.uvs[0] = 0 - offsetX; + sprite.uvs[1] = 0 - offsetY; + + sprite.uvs[2] = (1 * scaleX) -offsetX; + sprite.uvs[3] = 0 - offsetY; + + sprite.uvs[4] = (1 *scaleX) - offsetX; + sprite.uvs[5] = (1 *scaleY) - offsetY; + + sprite.uvs[6] = 0 - offsetX; + sprite.uvs[7] = (1 *scaleY) - offsetY; + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) + + this.renderStrip(sprite, projectionMatrix); +} + +/** + * Initializes a strip to be rendered + * + * @method initStrip + * @param strip {Strip} The strip to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) +{ + // build the strip! + var gl = this.gl; + var shaderProgram = this.shaderProgram; + + strip._vertexBuffer = gl.createBuffer(); + strip._indexBuffer = gl.createBuffer(); + strip._uvBuffer = gl.createBuffer(); + strip._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); + + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.WebGLFilterManager = function(transparent) +{ + this.transparent = transparent; + + this.filterStack = []; + this.texturePool = []; + + this.offsetX = 0; + this.offsetY = 0; + + this.initShaderBuffers(); +} + +// API + +PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) +{ + this.width = projection.x * 2; + this.height = -projection.y * 2; + this.buffer = buffer; +} + +PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) +{ + var gl = PIXI.gl; + + // filter program + // OPTIMISATION - the first filter is free if its a simple color change? + this.filterStack.push(filterBlock); + + var filter = filterBlock.filterPasses[0]; + + + + this.offsetX += filterBlock.target.filterArea.x; + this.offsetY += filterBlock.target.filterArea.y; + + + + + + var texture = this.texturePool.pop(); + if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); + + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + this.getBounds(filterBlock.target); + + // addpadding? + //displayObject.filterArea.x + + var filterArea = filterBlock.target.filterArea; + + var padidng = filter.padding; + filterArea.x -= padidng; + filterArea.y -= padidng; + filterArea.width += padidng * 2; + filterArea.height += padidng * 2; + + // cap filter to screen size.. + if(filterArea.x < 0)filterArea.x = 0; + if(filterArea.width > this.width)filterArea.width = this.width; + if(filterArea.y < 0)filterArea.y = 0; + if(filterArea.height > this.height)filterArea.height = this.height; + + + //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); + + // console.log(filterArea) + // set view port + gl.viewport(0, 0, filterArea.width, filterArea.height); + + PIXI.projection.x = filterArea.width/2; + PIXI.projection.y = -filterArea.height/2; + + PIXI.offset.x = -filterArea.x; + PIXI.offset.y = -filterArea.y; + + //console.log(PIXI.defaultShader.projectionVector) + // update projection + gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); + //PIXI.primitiveProgram + + gl.colorMask(true, true, true, true); + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + //filter.texture = texture; + filterBlock._glFilterTexture = texture; + + //console.log("PUSH") +} + + +PIXI.WebGLFilterManager.prototype.popFilter = function() +{ + + var gl = PIXI.gl; + + var filterBlock = this.filterStack.pop(); + + + + var filterArea = filterBlock.target.filterArea; + + var texture = filterBlock._glFilterTexture; + + if(filterBlock.filterPasses.length > 1) + { + gl.viewport(0, 0, filterArea.width, filterArea.height); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = 0; + this.vertexArray[1] = filterArea.height; + + this.vertexArray[2] = filterArea.width; + this.vertexArray[3] = filterArea.height; + + this.vertexArray[4] = 0; + this.vertexArray[5] = 0; + + this.vertexArray[6] = filterArea.width; + this.vertexArray[7] = 0; + + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + // nnow set the uvs.. + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + var inputTexture = texture; + var outputTexture = this.texturePool.pop(); + if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); + + // need to clear this FBO as it may have some left over elements from a prvious filter. + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.disable(gl.BLEND); + + for (var i = 0; i < filterBlock.filterPasses.length-1; i++) + { + var filterPass = filterBlock.filterPasses[i]; + + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); + + // draw texture.. + //filterPass.applyFilterPass(filterArea.width, filterArea.height); + this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); + + // swap the textures.. + var temp = inputTexture; + inputTexture = outputTexture; + outputTexture = temp; + + }; + + gl.enable(gl.BLEND); + + texture = inputTexture; + this.texturePool.push(outputTexture); + } + + var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; + + this.offsetX -= filterArea.x; + this.offsetY -= filterArea.y; + + + var sizeX = this.width; + var sizeY = this.height; + + var offsetX = 0; + var offsetY = 0; + + var buffer = this.buffer; + + // time to render the filters texture to the previous scene + if(this.filterStack.length === 0) + { + gl.colorMask(true, true, true, this.transparent); + } + else + { + var currentFilter = this.filterStack[this.filterStack.length-1]; + var filterArea = currentFilter.target.filterArea; + + sizeX = filterArea.width; + sizeY = filterArea.height; + + offsetX = filterArea.x; + offsetY = filterArea.y; + + buffer = currentFilter._glFilterTexture.frameBuffer; + } + + + + // TODO need toremove thease global elements.. + PIXI.projection.x = sizeX/2; + PIXI.projection.y = -sizeY/2; + + PIXI.offset.x = offsetX; + PIXI.offset.y = offsetY; + + + var filterArea = filterBlock.target.filterArea; + var x = filterArea.x-offsetX; + var y = filterArea.y-offsetY; + + // update the buffers.. + // make sure to flip the y! + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = x; + this.vertexArray[1] = y + filterArea.height; + + this.vertexArray[2] = x + filterArea.width; + this.vertexArray[3] = y + filterArea.height; + + this.vertexArray[4] = x; + this.vertexArray[5] = y; + + this.vertexArray[6] = x + filterArea.width; + this.vertexArray[7] = y; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + gl.viewport(0, 0, sizeX, sizeY); + // bind the buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + // apply! + //filter.applyFilterPass(sizeX, sizeY); + this.applyFilterPass(filter, filterArea, sizeX, sizeY); + + // now restore the regular shader.. + gl.useProgram(PIXI.defaultShader.program); + gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); + + // return the texture to the pool + this.texturePool.push(texture); + filterBlock._glFilterTexture = null; +} + +PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) +{ + // use program + var gl = PIXI.gl; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader; + } + + var shader = filter.shader; + + // set the shader + gl.useProgram(shader.program); + + gl.uniform2f(shader.projectionVector, width/2, -height/2); + gl.uniform2f(shader.offsetVector, 0,0) + + if(filter.uniforms.dimensions) + { + //console.log(filter.uniforms.dimensions) + filter.uniforms.dimensions.value[0] = this.width;//width; + filter.uniforms.dimensions.value[1] = this.height;//height; + filter.uniforms.dimensions.value[2] = this.vertexArray[0]; + filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; + // console.log(this.vertexArray[5]) + } + + shader.syncUniforms(); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + // draw the filter... + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); +} + +PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() +{ + var gl = PIXI.gl; + + // create some buffers + this.vertexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + // bind and upload the vertexs.. + // keep a refferance to the vertexFloatData.. + this.vertexArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.vertexArray, + gl.STATIC_DRAW); + + + // bind and upload the uv buffer + this.uvArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.uvArray, + gl.STATIC_DRAW); + + // bind and upload the index + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData( + gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array([0, 1, 2, 1, 3, 2]), + gl.STATIC_DRAW); +} + +PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) +{ + // time to get the width and height of the object! + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; + var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + + var maxX = -Infinity; + var maxY = -Infinity; + + var minX = Infinity; + var minY = Infinity; + + do + { + // TODO can be optimized! - what if there is no scale / rotation? + + if(tempObject.visible) + { + if(tempObject instanceof PIXI.Sprite) + { + width = tempObject.texture.frame.width; + height = tempObject.texture.frame.height; + + // TODO trim?? + aX = tempObject.anchor.x; + aY = tempObject.anchor.y; + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + doTest = true; + } + else if(tempObject instanceof PIXI.Graphics) + { + tempObject.updateFilterBounds(); + + var bounds = tempObject.bounds; + + width = bounds.width; + height = bounds.height; + + w0 = bounds.x + w1 = bounds.x + bounds.width; + + h0 = bounds.y + h1 = bounds.y + bounds.height; + + doTest = true; + } + } + + if(doTest) + { + worldTransform = tempObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + x1 = a * w1 + c * h1 + tx; + y1 = d * h1 + b * w1 + ty; + + x2 = a * w0 + c * h1 + tx; + y2 = d * h1 + b * w0 + ty; + + x3 = a * w0 + c * h0 + tx; + y3 = d * h0 + b * w0 + ty; + + x4 = a * w1 + c * h0 + tx; + y4 = d * h0 + b * w1 + ty; + + minX = x1 < minX ? x1 : minX; + minX = x2 < minX ? x2 : minX; + minX = x3 < minX ? x3 : minX; + minX = x4 < minX ? x4 : minX; + + minY = y1 < minY ? y1 : minY; + minY = y2 < minY ? y2 : minY; + minY = y3 < minY ? y3 : minY; + minY = y4 < minY ? y4 : minY; + + maxX = x1 > maxX ? x1 : maxX; + maxX = x2 > maxX ? x2 : maxX; + maxX = x3 > maxX ? x3 : maxX; + maxX = x4 > maxX ? x4 : maxX; + + maxY = y1 > maxY ? y1 : maxY; + maxY = y2 > maxY ? y2 : maxY; + maxY = y3 > maxY ? y3 : maxY; + maxY = y4 > maxY ? y4 : maxY; + } + + doTest = false; + tempObject = tempObject._iNext; + + } + while(tempObject != testObject) + + // maximum bounds is the size of the screen.. + //minX = minX > 0 ? minX : 0; + //minY = minY > 0 ? minY : 0; + + displayObject.filterArea.x = minX; + displayObject.filterArea.y = minY; + +// console.log(maxX+ " : " + minX) + displayObject.filterArea.width = maxX - minX; + displayObject.filterArea.height = maxY - minY; +} + +PIXI.FilterTexture = function(width, height) +{ + var gl = PIXI.gl; + + // next time to create a frame buffer and texture + this.frameBuffer = gl.createFramebuffer(); + this.texture = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); + + this.resize(width, height); +} + +PIXI.FilterTexture.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + var gl = PIXI.gl; + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class CanvasRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + */ +PIXI.CanvasRenderer = function(width, height, view, transparent) +{ + this.transparent = transparent; + + /** + * The width of the canvas view + * + * @property width + * @type Number + * @default 800 + */ + this.width = width || 800; + + /** + * The height of the canvas view + * + * @property height + * @type Number + * @default 600 + */ + this.height = height || 600; + + /** + * The canvas element that the everything is drawn to + * + * @property view + * @type Canvas + */ + this.view = view || document.createElement( 'canvas' ); + + /** + * The canvas context that the everything is drawn to + * @property context + * @type Canvas 2d Context + */ + this.context = this.view.getContext("2d"); + + this.refresh = true; + // hack to enable some hardware acceleration! + //this.view.style["transform"] = "translatez(0)"; + + this.view.width = this.width; + this.view.height = this.height; + this.count = 0; +} + +// constructor +PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; + +/** + * Renders the stage to its canvas view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.CanvasRenderer.prototype.render = function(stage) +{ + + //stage.__childrenAdded = []; + //stage.__childrenRemoved = []; + + // update textures if need be + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; + + PIXI.visibleCount++; + stage.updateTransform(); + + // update the background color + if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; + + this.context.setTransform(1,0,0,1,0,0); + this.context.clearRect(0, 0, this.width, this.height) + this.renderDisplayObject(stage); + //as + + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // remove frame updates.. + if(PIXI.Texture.frameUpdates.length > 0) + { + PIXI.Texture.frameUpdates = []; + } + + +} + +/** + * resizes the canvas view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the canvas view + * @param height {Number} the new height of the canvas view + */ +PIXI.CanvasRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; +} + +/** + * Renders a display object + * + * @method renderDisplayObject + * @param displayObject {DisplayObject} The displayObject to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +{ + // no loger recurrsive! + var transform; + var context = this.context; + + context.globalCompositeOperation = 'source-over'; + + // one the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + transform = displayObject.worldTransform; + + if(!displayObject.visible) + { + displayObject = displayObject.last._iNext; + continue; + } + + if(!displayObject.renderable) + { + displayObject = displayObject._iNext; + continue; + } + + if(displayObject instanceof PIXI.Sprite) + { + + var frame = displayObject.texture.frame; + + if(frame && frame.width && frame.height) + { + context.globalAlpha = displayObject.worldAlpha; + + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + + context.drawImage(displayObject.texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.y) * -frame.height, + frame.width, + frame.height); + } + } + else if(displayObject instanceof PIXI.Strip) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderStrip(displayObject); + } + else if(displayObject instanceof PIXI.TilingSprite) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderTilingSprite(displayObject); + } + else if(displayObject instanceof PIXI.CustomRenderable) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + displayObject.renderCanvas(this); + } + else if(displayObject instanceof PIXI.Graphics) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + PIXI.CanvasGraphics.renderGraphics(displayObject, context); + } + else if(displayObject instanceof PIXI.FilterBlock) + { + if(displayObject.data instanceof PIXI.Graphics) + { + var mask = displayObject.data; + + if(displayObject.open) + { + context.save(); + + var cacheAlpha = mask.alpha; + var maskTransform = mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(mask, context); + context.clip(); + + mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } + } + else + { + // only masks supported right now! + } + } + // count++ + displayObject = displayObject._iNext; + + + } + while(displayObject != testObject) + + +} + +/** + * Renders a flat strip + * + * @method renderStripFlat + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) +{ + var context = this.context; + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + + context.beginPath(); + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + }; + + context.fillStyle = "#FF0000"; + context.fill(); + context.closePath(); +} + +/** + * Renders a tiling sprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tilingsprite to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) +{ + var context = this.context; + + context.globalAlpha = sprite.worldAlpha; + + if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); + + context.beginPath(); + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + // offset + context.scale(tileScale.x,tileScale.y); + context.translate(tilePosition.x, tilePosition.y); + + context.fillStyle = sprite.__tilePattern; + context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); + + context.scale(1/tileScale.x, 1/tileScale.y); + context.translate(-tilePosition.x, -tilePosition.y); + + context.closePath(); +} + +/** + * Renders a strip + * + * @method renderStrip + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStrip = function(strip) +{ + var context = this.context; + + // draw triangles!! + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; + var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; + + + context.save(); + context.beginPath(); + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + context.closePath(); + + context.clip(); + + + // Compute matrix transform + var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; + var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; + var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; + var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; + var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; + var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; + var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; + + + + + context.transform(delta_a/delta, delta_d/delta, + delta_b/delta, delta_e/delta, + delta_c/delta, delta_f/delta); + + context.drawImage(strip.texture.baseTexture.source, 0, 0); + context.restore(); + }; + +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A set of functions used by the canvas renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.CanvasGraphics = function() +{ + +} + + +/* + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphics = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + for (var i=0; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); + + context.lineWidth = data.lineWidth; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + + if(data.fillColor || data.fillColor === 0) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fillRect(points[0], points[1], points[2], points[3]); + + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.strokeRect(points[0], points[1], points[2], points[3]); + } + + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + + }; +} + +/* + * Renders a graphics mask + * + * @static + * @private + * @method renderGraphicsMask + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + var len = graphics.graphicsData.length; + if(len === 0)return; + + if(len > 1) + { + len = 1; + console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") + } + + for (var i=0; i < 1; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + } + else if(data.type == PIXI.Graphics.RECT) + { + context.beginPath(); + context.rect(points[0], points[1], points[2], points[3]); + context.closePath(); + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + + + }; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * It is important to know that with the webGL renderer only simple polys can be filled at this stage + * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png + * + * @class Graphics + * @extends DisplayObjectContainer + * @constructor + */ +PIXI.Graphics = function() +{ + PIXI.DisplayObjectContainer.call( this ); + + this.renderable = true; + + /** + * The alpha of the fill of this graphics object + * + * @property fillAlpha + * @type Number + */ + this.fillAlpha = 1; + + /** + * The width of any lines drawn + * + * @property lineWidth + * @type Number + */ + this.lineWidth = 0; + + /** + * The color of any lines drawn + * + * @property lineColor + * @type String + */ + this.lineColor = "black"; + + /** + * Graphics data + * + * @property graphicsData + * @type Array + * @private + */ + this.graphicsData = []; + + /** + * Current path + * + * @property currentPath + * @type Object + * @private + */ + this.currentPath = {points:[]}; +} + +// constructor +PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Graphics.prototype.constructor = PIXI.Graphics; + +/** + * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. + * + * @method lineStyle + * @param lineWidth {Number} width of the line to draw, will update the object's stored style + * @param color {Number} color of the line to draw, will update the object's stored style + * @param alpha {Number} alpha of the line to draw, will update the object's stored style + */ +PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.lineWidth = lineWidth || 0; + this.lineColor = color || 0; + this.lineAlpha = (alpha == undefined) ? 1 : alpha; + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.graphicsData.push(this.currentPath); +} + +/** + * Moves the current drawing position to (x, y). + * + * @method moveTo + * @param x {Number} the X coord to move to + * @param y {Number} the Y coord to move to + */ +PIXI.Graphics.prototype.moveTo = function(x, y) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.currentPath.points.push(x, y); + + this.graphicsData.push(this.currentPath); +} + +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coord to draw to + * @param y {Number} the Y coord to draw to + */ +PIXI.Graphics.prototype.lineTo = function(x, y) +{ + this.currentPath.points.push(x, y); + this.dirty = true; +} + +/** + * Specifies a simple one-color fill that subsequent calls to other Graphics methods + * (such as lineTo() or drawCircle()) use when drawing. + * + * @method beginFill + * @param color {uint} the color of the fill + * @param alpha {Number} the alpha + */ +PIXI.Graphics.prototype.beginFill = function(color, alpha) +{ + this.filling = true; + this.fillColor = color || 0; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; +} + +/** + * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. + * + * @method endFill + */ +PIXI.Graphics.prototype.endFill = function() +{ + this.filling = false; + this.fillColor = null; + this.fillAlpha = 1; +} + +/** + * @method drawRect + * + * @param x {Number} The X coord of the top-left of the rectangle + * @param y {Number} The Y coord of the top-left of the rectangle + * @param width {Number} The width of the rectangle + * @param height {Number} The height of the rectangle + */ +PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.RECT}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws a circle. + * + * @method drawCircle + * @param x {Number} The X coord of the center of the circle + * @param y {Number} The Y coord of the center of the circle + * @param radius {Number} The radius of the circle + */ +PIXI.Graphics.prototype.drawCircle = function( x, y, radius) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws an elipse. + * + * @method drawElipse + * @param x {Number} + * @param y {Number} + * @param width {Number} + * @param height {Number} + */ +PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.ELIP}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. + * + * @method clear + */ +PIXI.Graphics.prototype.clear = function() +{ + this.lineWidth = 0; + this.filling = false; + + this.dirty = true; + this.clearDirty = true; + this.graphicsData = []; + + this.bounds = null//new PIXI.Rectangle(); +} + + +PIXI.Graphics.prototype.updateFilterBounds = function() +{ + if(!this.bounds) + { + var minX = Infinity; + var maxX = -Infinity; + + var minY = Infinity; + var maxY = -Infinity; + + var points, x, y; + + for (var i = 0; i < this.graphicsData.length; i++) { + + + var data = this.graphicsData[i]; + var type = data.type; + var lineWidth = data.lineWidth; + + points = data.points; + + if(type === PIXI.Graphics.RECT) + { + x = points.x - lineWidth/2; + y = points.y - lineWidth/2; + var width = points.width + lineWidth; + var height = points.height + lineWidth; + + minX = x < minX ? x : minX; + maxX = x + width > maxX ? x + width : maxX; + + minY = y < minY ? x : minY; + maxY = y + height > maxY ? y + height : maxY; + } + else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + { + x = points.x; + y = points.y; + var radius = points.radius + lineWidth/2; + + minX = x - radius < minX ? x - radius : minX; + maxX = x + radius > maxX ? x + radius : maxX; + + minY = y - radius < minY ? y - radius : minY; + maxY = y + radius > maxY ? y + radius : maxY; + } + else + { + // POLY + for (var j = 0; j < points.length; j+=2) + { + + x = points[j]; + y = points[j+1]; + + minX = x-lineWidth < minX ? x-lineWidth : minX; + maxX = x+lineWidth > maxX ? x+lineWidth : maxX; + + minY = y-lineWidth < minY ? y-lineWidth : minY; + maxY = y+lineWidth > maxY ? y+lineWidth : maxY; + }; + } + + }; + + this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + + } + +// console.log(this.bounds); +} + +// SOME TYPES: +PIXI.Graphics.POLY = 0; +PIXI.Graphics.RECT = 1; +PIXI.Graphics.CIRC = 2; +PIXI.Graphics.ELIP = 3; + +/** + * @author Mat Groves http://matgroves.com/ + */ + +PIXI.Strip = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + this.texture = texture; + this.blendMode = PIXI.blendModes.NORMAL; + + try + { + this.uvs = new Float32Array([0, 1, + 1, 1, + 1, 0, 0,1]); + + this.verticies = new Float32Array([0, 0, + 0,0, + 0,0, 0, + 0, 0]); + + this.colors = new Float32Array([1, 1, 1, 1]); + + this.indices = new Uint16Array([0, 1, 2, 3]); + } + catch(error) + { + this.uvs = [0, 1, + 1, 1, + 1, 0, 0,1]; + + this.verticies = [0, 0, + 0,0, + 0,0, 0, + 0, 0]; + + this.colors = [1, 1, 1, 1]; + + this.indices = [0, 1, 2, 3]; + } + + + /* + this.uvs = new Float32Array() + this.verticies = new Float32Array() + this.colors = new Float32Array() + this.indices = new Uint16Array() +*/ + this.width = width; + this.height = height; + + // load the texture! + if(texture.baseTexture.hasLoaded) + { + this.width = this.texture.frame.width; + this.height = this.texture.frame.height; + this.updateFrame = true; + } + else + { + this.onTextureUpdateBind = this.onTextureUpdate.bind(this); + this.texture.addEventListener( 'update', this.onTextureUpdateBind ); + } + + this.renderable = true; +} + +// constructor +PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Strip.prototype.constructor = PIXI.Strip; + +PIXI.Strip.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.width = texture.frame.width; + this.height = texture.frame.height; + this.updateFrame = true; +} + +PIXI.Strip.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} +// some helper functions.. + + +/** + * @author Mat Groves http://matgroves.com/ + */ + + +PIXI.Rope = function(texture, points) +{ + PIXI.Strip.call( this, texture ); + this.points = points; + + try + { + this.verticies = 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); + } + catch(error) + { + this.verticies = verticies + + this.uvs = uvs + this.colors = colors + this.indices = indices + } + + this.refresh(); +} + + +// constructor +PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); +PIXI.Rope.prototype.constructor = PIXI.Rope; + +PIXI.Rope.prototype.refresh = function() +{ + var points = this.points; + if(points.length < 1)return; + + var uvs = this.uvs + var indices = this.indices; + var colors = this.colors; + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + + uvs[0] = 0 + uvs[1] = 1 + uvs[2] = 0 + uvs[3] = 1 + + colors[0] = 1; + colors[1] = 1; + + indices[0] = 0; + indices[1] = 1; + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + // time to do some smart drawing! + var amount = i/(total-1) + + if(i%2) + { + uvs[index] = amount; + uvs[index+1] = 0; + + uvs[index+2] = amount + uvs[index+3] = 1 + + } + else + { + uvs[index] = amount + uvs[index+1] = 0 + + uvs[index+2] = amount + uvs[index+3] = 1 + } + + index = i * 2; + colors[index] = 1; + colors[index+1] = 1; + + index = i * 2; + indices[index] = index; + indices[index + 1] = index + 1; + + lastPoint = point; + } +} + +PIXI.Rope.prototype.updateTransform = function() +{ + + var points = this.points; + if(points.length < 1)return; + + var verticies = this.verticies + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + verticies[0] = point.x + perp.x + verticies[1] = point.y + perp.y //+ 200 + verticies[2] = point.x - perp.x + verticies[3] = point.y - perp.y//+200 + // time to do some smart drawing! + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + + if(i < points.length-1) + { + nextPoint = points[i+1]; + } + else + { + nextPoint = point + } + + perp.y = -(nextPoint.x - lastPoint.x); + perp.x = nextPoint.y - lastPoint.y; + + var ratio = (1 - (i / (total-1))) * 10; + if(ratio > 1)ratio = 1; + + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); + var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; + perp.x /= perpLength; + perp.y /= perpLength; + + perp.x *= num; + perp.y *= num; + + verticies[index] = point.x + perp.x + verticies[index+1] = point.y + perp.y + verticies[index+2] = point.x - perp.x + verticies[index+3] = point.y - perp.y + + lastPoint = point; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); +} + +PIXI.Rope.prototype.setTexture = function(texture) +{ + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * A tiling sprite is a fast way of rendering a tiling image + * + * @class TilingSprite + * @extends DisplayObjectContainer + * @constructor + * @param texture {Texture} the texture of the tiling sprite + * @param width {Number} the width of the tiling sprite + * @param height {Number} the height of the tiling sprite + */ +PIXI.TilingSprite = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * The texture that the sprite is using + * + * @property texture + * @type Texture + */ + this.texture = texture; + + /** + * The width of the tiling sprite + * + * @property width + * @type Number + */ + this.width = width; + + /** + * The height of the tiling sprite + * + * @property height + * @type Number + */ + this.height = height; + + /** + * The scaling of the image that is being tiled + * + * @property tileScale + * @type Point + */ + this.tileScale = new PIXI.Point(1,1); + + /** + * The offset position of the image that is being tiled + * + * @property tilePosition + * @type Point + */ + this.tilePosition = new PIXI.Point(0,0); + + this.renderable = true; + + this.blendMode = PIXI.blendModes.NORMAL +} + +// constructor +PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; + +/** + * Sets the texture of the tiling sprite + * + * @method setTexture + * @param texture {Texture} The PIXI texture that is displayed by the sprite + */ +PIXI.TilingSprite.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + +/** + * When the texture is updated, this event will fire to update the frame + * + * @method onTextureUpdate + * @param event + * @private + */ +PIXI.TilingSprite.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi + * + * Awesome JS run time provided by EsotericSoftware + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +/** + * A class that enables the you to import and run your spine animations in pixi. + * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class + * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source + * + * @class Spine + * @extends DisplayObjectContainer + * @constructor + * @param url {String} The url of the spine anim file to be used + */ +PIXI.Spine = function (url) { + PIXI.DisplayObjectContainer.call(this); + + this.spineData = PIXI.AnimCache[url]; + + if (!this.spineData) { + throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); + } + + this.skeleton = new spine.Skeleton(this.spineData); + this.skeleton.updateWorldTransform(); + + this.stateData = new spine.AnimationStateData(this.spineData); + this.state = new spine.AnimationState(this.stateData); + + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.Spine.prototype.constructor = PIXI.Spine; + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); + this.state.apply(this.skeleton); + this.skeleton.updateWorldTransform(); + + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } + + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; + } + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; + } + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; + +/* + * Awesome JS run time provided by EsotericSoftware + * + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +var spine = {}; + +spine.BoneData = function (name, parent) { + this.name = name; + this.parent = parent; +}; +spine.BoneData.prototype = { + length: 0, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1 +}; + +spine.SlotData = function (name, boneData) { + this.name = name; + this.boneData = boneData; +}; +spine.SlotData.prototype = { + r: 1, g: 1, b: 1, a: 1, + attachmentName: null +}; + +spine.Bone = function (boneData, parent) { + this.data = boneData; + this.parent = parent; + this.setToSetupPose(); +}; +spine.Bone.yDown = false; +spine.Bone.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + m00: 0, m01: 0, worldX: 0, // a b x + m10: 0, m11: 0, worldY: 0, // c d y + worldRotation: 0, + worldScaleX: 1, worldScaleY: 1, + updateWorldTransform: function (flipX, flipY) { + var parent = this.parent; + if (parent != null) { + this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; + this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; + this.worldScaleX = parent.worldScaleX * this.scaleX; + this.worldScaleY = parent.worldScaleY * this.scaleY; + this.worldRotation = parent.worldRotation + this.rotation; + } else { + this.worldX = this.x; + this.worldY = this.y; + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + this.worldRotation = this.rotation; + } + var radians = this.worldRotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + this.m00 = cos * this.worldScaleX; + this.m10 = sin * this.worldScaleX; + this.m01 = -sin * this.worldScaleY; + this.m11 = cos * this.worldScaleY; + if (flipX) { + this.m00 = -this.m00; + this.m01 = -this.m01; + } + if (flipY) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + if (spine.Bone.yDown) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + }, + setToSetupPose: function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + } +}; + +spine.Slot = function (slotData, skeleton, bone) { + this.data = slotData; + this.skeleton = skeleton; + this.bone = bone; + this.setToSetupPose(); +}; +spine.Slot.prototype = { + r: 1, g: 1, b: 1, a: 1, + _attachmentTime: 0, + attachment: null, + setAttachment: function (attachment) { + this.attachment = attachment; + this._attachmentTime = this.skeleton.time; + }, + setAttachmentTime: function (time) { + this._attachmentTime = this.skeleton.time - time; + }, + getAttachmentTime: function () { + return this.skeleton.time - this._attachmentTime; + }, + setToSetupPose: function () { + var data = this.data; + this.r = data.r; + this.g = data.g; + this.b = data.b; + this.a = data.a; + + var slotDatas = this.skeleton.data.slots; + for (var i = 0, n = slotDatas.length; i < n; i++) { + if (slotDatas[i] == data) { + this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); + break; + } + } + } +}; + +spine.Skin = function (name) { + this.name = name; + this.attachments = {}; +}; +spine.Skin.prototype = { + addAttachment: function (slotIndex, name, attachment) { + this.attachments[slotIndex + ":" + name] = attachment; + }, + getAttachment: function (slotIndex, name) { + return this.attachments[slotIndex + ":" + name]; + }, + _attachAll: function (skeleton, oldSkin) { + for (var key in oldSkin.attachments) { + var colon = key.indexOf(":"); + var slotIndex = parseInt(key.substring(0, colon)); + var name = key.substring(colon + 1); + var slot = skeleton.slots[slotIndex]; + if (slot.attachment && slot.attachment.name == name) { + var attachment = this.getAttachment(slotIndex, name); + if (attachment) slot.setAttachment(attachment); + } + } + } +}; + +spine.Animation = function (name, timelines, duration) { + this.name = name; + this.timelines = timelines; + this.duration = duration; +}; +spine.Animation.prototype = { + apply: function (skeleton, time, loop) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, 1); + }, + mix: function (skeleton, time, loop, alpha) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, alpha); + } +}; + +spine.binarySearch = function (values, target, step) { + var low = 0; + var high = Math.floor(values.length / step) - 2; + if (high == 0) return step; + var current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } +}; +spine.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; +}; + +spine.Curves = function (frameCount) { + this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... + this.curves.length = (frameCount - 1) * 6; +}; +spine.Curves.prototype = { + setLinear: function (frameIndex) { + this.curves[frameIndex * 6] = 0/*LINEAR*/; + }, + setStepped: function (frameIndex) { + this.curves[frameIndex * 6] = -1/*STEPPED*/; + }, + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { + var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; + var subdiv_step2 = subdiv_step * subdiv_step; + var subdiv_step3 = subdiv_step2 * subdiv_step; + var pre1 = 3 * subdiv_step; + var pre2 = 3 * subdiv_step2; + var pre4 = 6 * subdiv_step2; + var pre5 = 6 * subdiv_step3; + var tmp1x = -cx1 * 2 + cx2; + var tmp1y = -cy1 * 2 + cy2; + var tmp2x = (cx1 - cx2) * 3 + 1; + var tmp2y = (cy1 - cy2) * 3 + 1; + var i = frameIndex * 6; + var curves = this.curves; + curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; + curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; + curves[i + 4] = tmp2x * pre5; + curves[i + 5] = tmp2y * pre5; + }, + getCurvePercent: function (frameIndex, percent) { + percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); + var curveIndex = frameIndex * 6; + var curves = this.curves; + var dfx = curves[curveIndex]; + if (!dfx/*LINEAR*/) return percent; + if (dfx == -1/*STEPPED*/) return 0; + var dfy = curves[curveIndex + 1]; + var ddfx = curves[curveIndex + 2]; + var ddfy = curves[curveIndex + 3]; + var dddfx = curves[curveIndex + 4]; + var dddfy = curves[curveIndex + 5]; + var x = dfx, y = dfy; + var i = 10/*BEZIER_SEGMENTS*/ - 2; + while (true) { + if (x >= percent) { + var lastX = x - dfx; + var lastY = y - dfy; + return lastY + (y - lastY) * (percent - lastX) / (x - lastX); + } + if (i == 0) break; + i--; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +}; + +spine.RotateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, angle, ... + this.frames.length = frameCount * 2; +}; +spine.RotateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, angle) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = angle; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 2]) { // Time is after last frame. + var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 2); + var lastFrameValue = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); + + var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +}; + +spine.TranslateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.TranslateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; + } +}; + +spine.ScaleTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.ScaleTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; + } +}; + +spine.ColorTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, r, g, b, a, ... + this.frames.length = frameCount * 5; +}; +spine.ColorTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 5; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = r; + this.frames[frameIndex + 2] = g; + this.frames[frameIndex + 3] = b; + this.frames[frameIndex + 4] = a; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var slot = skeleton.slots[this.slotIndex]; + + if (time >= frames[frames.length - 5]) { // Time is after last frame. + var i = frames.length - 1; + slot.r = frames[i - 3]; + slot.g = frames[i - 2]; + slot.b = frames[i - 1]; + slot.a = frames[i]; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 5); + var lastFrameR = frames[frameIndex - 4]; + var lastFrameG = frames[frameIndex - 3]; + var lastFrameB = frames[frameIndex - 2]; + var lastFrameA = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); + + var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; + var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; + var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; + var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +}; + +spine.AttachmentTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, ... + this.frames.length = frameCount; + this.attachmentNames = []; // time, ... + this.attachmentNames.length = frameCount; +}; +spine.AttachmentTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = spine.binarySearch(frames, time, 1) - 1; + + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); + } +}; + +spine.SkeletonData = function () { + this.bones = []; + this.slots = []; + this.skins = []; + this.animations = []; +}; +spine.SkeletonData.prototype = { + defaultSkin: null, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + if (slots[i].name == slotName) return slot[i]; + } + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + }, + /** @return May be null. */ + findSkin: function (skinName) { + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) + if (skins[i].name == skinName) return skins[i]; + return null; + }, + /** @return May be null. */ + findAnimation: function (animationName) { + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) + if (animations[i].name == animationName) return animations[i]; + return null; + } +}; + +spine.Skeleton = function (skeletonData) { + this.data = skeletonData; + + this.bones = []; + for (var i = 0, n = skeletonData.bones.length; i < n; i++) { + var boneData = skeletonData.bones[i]; + var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; + this.bones.push(new spine.Bone(boneData, parent)); + } + + this.slots = []; + this.drawOrder = []; + for (var i = 0, n = skeletonData.slots.length; i < n; i++) { + var slotData = skeletonData.slots[i]; + var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; + var slot = new spine.Slot(slotData, this, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } +}; +spine.Skeleton.prototype = { + x: 0, y: 0, + skin: null, + r: 1, g: 1, b: 1, a: 1, + time: 0, + flipX: false, flipY: false, + /** Updates the world transform for each bone. */ + updateWorldTransform: function () { + var flipX = this.flipX; + var flipY = this.flipY; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].updateWorldTransform(flipX, flipY); + }, + /** Sets the bones and slots to their setup pose values. */ + setToSetupPose: function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }, + setBonesToSetupPose: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + }, + setSlotsToSetupPose: function () { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(i); + }, + /** @return May return null. */ + getRootBone: function () { + return this.bones.length == 0 ? null : this.bones[0]; + }, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return slots[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + }, + setSkinByName: function (skinName) { + var skin = this.data.findSkin(skinName); + if (!skin) throw "Skin not found: " + skinName; + this.setSkin(skin); + }, + /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments + * from the new skin are attached if the corresponding attachment from the old skin was attached. + * @param newSkin May be null. */ + setSkin: function (newSkin) { + if (this.skin && newSkin) newSkin._attachAll(this, this.skin); + this.skin = newSkin; + }, + /** @return May be null. */ + getAttachmentBySlotName: function (slotName, attachmentName) { + return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); + }, + /** @return May be null. */ + getAttachmentBySlotIndex: function (slotIndex, attachmentName) { + if (this.skin) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }, + /** @param attachmentName May be null. */ + setAttachment: function (slotName, attachmentName) { + var slots = this.slots; + for (var i = 0, n = slots.size; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; + } + slot.setAttachment(attachment); + return; + } + } + throw "Slot not found: " + slotName; + }, + update: function (delta) { + time += delta; + } +}; + +spine.AttachmentType = { + region: 0 +}; + +spine.RegionAttachment = function () { + this.offset = []; + this.offset.length = 8; + this.uvs = []; + this.uvs.length = 8; +}; +spine.RegionAttachment.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + width: 0, height: 0, + rendererObject: null, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + setUVs: function (u, v, u2, v2, rotate) { + var uvs = this.uvs; + if (rotate) { + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v2; + uvs[4/*X3*/] = u; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v; + uvs[0/*X1*/] = u2; + uvs[1/*Y1*/] = v2; + } else { + uvs[0/*X1*/] = u; + uvs[1/*Y1*/] = v2; + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v; + uvs[4/*X3*/] = u2; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v2; + } + }, + updateOffset: function () { + var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; + var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; + var localX2 = localX + this.regionWidth * regionScaleX; + var localY2 = localY + this.regionHeight * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[0/*X1*/] = localXCos - localYSin; + offset[1/*Y1*/] = localYCos + localXSin; + offset[2/*X2*/] = localXCos - localY2Sin; + offset[3/*Y2*/] = localY2Cos + localXSin; + offset[4/*X3*/] = localX2Cos - localY2Sin; + offset[5/*Y3*/] = localY2Cos + localX2Sin; + offset[6/*X4*/] = localX2Cos - localYSin; + offset[7/*Y4*/] = localYCos + localX2Sin; + }, + computeVertices: function (x, y, bone, vertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00; + var m01 = bone.m01; + var m10 = bone.m10; + var m11 = bone.m11; + var offset = this.offset; + vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; + vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; + vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; + vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; + vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; + vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; + vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; + vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; + } +} + +spine.AnimationStateData = function (skeletonData) { + this.skeletonData = skeletonData; + this.animationToMixTime = {}; +}; +spine.AnimationStateData.prototype = { + defaultMix: 0, + setMixByName: function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (!from) throw "Animation not found: " + fromName; + var to = this.skeletonData.findAnimation(toName); + if (!to) throw "Animation not found: " + toName; + this.setMix(from, to, duration); + }, + setMix: function (from, to, duration) { + this.animationToMixTime[from.name + ":" + to.name] = duration; + }, + getMix: function (from, to) { + var time = this.animationToMixTime[from.name + ":" + to.name]; + return time ? time : this.defaultMix; + } +}; + +spine.AnimationState = function (stateData) { + this.data = stateData; + this.queue = []; +}; +spine.AnimationState.prototype = { + current: null, + previous: null, + currentTime: 0, + previousTime: 0, + currentLoop: false, + previousLoop: false, + mixTime: 0, + mixDuration: 0, + update: function (delta) { + this.currentTime += delta; + this.previousTime += delta; + this.mixTime += delta; + + if (this.queue.length > 0) { + var entry = this.queue[0]; + if (this.currentTime >= entry.delay) { + this._setAnimation(entry.animation, entry.loop); + this.queue.shift(); + } + } + }, + apply: function (skeleton) { + if (!this.current) return; + if (this.previous) { + this.previous.apply(skeleton, this.previousTime, this.previousLoop); + var alpha = this.mixTime / this.mixDuration; + if (alpha >= 1) { + alpha = 1; + this.previous = null; + } + this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); + } else + this.current.apply(skeleton, this.currentTime, this.currentLoop); + }, + clearAnimation: function () { + this.previous = null; + this.current = null; + this.queue.length = 0; + }, + _setAnimation: function (animation, loop) { + this.previous = null; + if (animation && this.current) { + this.mixDuration = this.data.getMix(this.current, animation); + if (this.mixDuration > 0) { + this.mixTime = 0; + this.previous = this.current; + this.previousTime = this.currentTime; + this.previousLoop = this.currentLoop; + } + } + this.current = animation; + this.currentLoop = loop; + this.currentTime = 0; + }, + /** @see #setAnimation(Animation, Boolean) */ + setAnimationByName: function (animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.setAnimation(animation, loop); + }, + /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. + * @param animation May be null. */ + setAnimation: function (animation, loop) { + this.queue.length = 0; + this._setAnimation(animation, loop); + }, + /** @see #addAnimation(Animation, Boolean, Number) */ + addAnimationByName: function (animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.addAnimation(animation, loop, delay); + }, + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimation: function (animation, loop, delay) { + var entry = {}; + entry.animation = animation; + entry.loop = loop; + + if (!delay || delay <= 0) { + var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; + if (previousAnimation != null) + delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); + else + delay = 0; + } + entry.delay = delay; + + this.queue.push(entry); + }, + /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ + isComplete: function () { + return !this.current || this.currentTime >= this.current.duration; + } +}; + +spine.SkeletonJson = function (attachmentLoader) { + this.attachmentLoader = attachmentLoader; +}; +spine.SkeletonJson.prototype = { + scale: 1, + readSkeletonData: function (root) { + var skeletonData = new spine.SkeletonData(); + + // Bones. + var bones = root["bones"]; + for (var i = 0, n = bones.length; i < n; i++) { + var boneMap = bones[i]; + var parent = null; + if (boneMap["parent"]) { + parent = skeletonData.findBone(boneMap["parent"]); + if (!parent) throw "Parent bone not found: " + boneMap["parent"]; + } + var boneData = new spine.BoneData(boneMap["name"], parent); + boneData.length = (boneMap["length"] || 0) * this.scale; + boneData.x = (boneMap["x"] || 0) * this.scale; + boneData.y = (boneMap["y"] || 0) * this.scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap["scaleX"] || 1; + boneData.scaleY = boneMap["scaleY"] || 1; + skeletonData.bones.push(boneData); + } + + // Slots. + var slots = root["slots"]; + for (var i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + var boneData = skeletonData.findBone(slotMap["bone"]); + if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; + var slotData = new spine.SlotData(slotMap["name"], boneData); + + var color = slotMap["color"]; + if (color) { + slotData.r = spine.SkeletonJson.toColor(color, 0); + slotData.g = spine.SkeletonJson.toColor(color, 1); + slotData.b = spine.SkeletonJson.toColor(color, 2); + slotData.a = spine.SkeletonJson.toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + + skeletonData.slots.push(slotData); + } + + // Skins. + var skins = root["skins"]; + for (var skinName in skins) { + if (!skins.hasOwnProperty(skinName)) continue; + var skinMap = skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + if (!skinMap.hasOwnProperty(slotName)) continue; + var slotIndex = skeletonData.findSlotIndex(slotName); + var slotEntry = skinMap[slotName]; + for (var attachmentName in slotEntry) { + if (!slotEntry.hasOwnProperty(attachmentName)) continue; + var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); + if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + + // Animations. + var animations = root["animations"]; + for (var animationName in animations) { + if (!animations.hasOwnProperty(animationName)) continue; + this.readAnimation(animationName, animations[animationName], skeletonData); + } + + return skeletonData; + }, + readAttachment: function (skin, name, map) { + name = map["name"] || name; + + var type = spine.AttachmentType[map["type"] || "region"]; + + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); + attachment.x = (map["x"] || 0) * this.scale; + attachment.y = (map["y"] || 0) * this.scale; + attachment.scaleX = map["scaleX"] || 1; + attachment.scaleY = map["scaleY"] || 1; + attachment.rotation = map["rotation"] || 0; + attachment.width = (map["width"] || 32) * this.scale; + attachment.height = (map["height"] || 32) * this.scale; + attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; + } + + throw "Unknown attachment type: " + type; + }, + + readAnimation: function (name, map, skeletonData) { + var timelines = []; + var duration = 0; + + var bones = map["bones"]; + for (var boneName in bones) { + if (!bones.hasOwnProperty(boneName)) continue; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw "Bone not found: " + boneName; + var boneMap = bones[boneName]; + + for (var timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + var values = boneMap[timelineName]; + if (timelineName == "rotate") { + var timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + + } else if (timelineName == "translate" || timelineName == "scale") { + var timeline; + var timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var x = (valueMap["x"] || 0) * timelineScale; + var y = (valueMap["y"] || 0) * timelineScale; + timeline.setFrame(frameIndex, valueMap["time"], x, y); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); + + } else + throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; + } + } + var slots = map["slots"]; + for (var slotName in slots) { + if (!slots.hasOwnProperty(slotName)) continue; + var slotMap = slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + + for (var timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + var values = slotMap[timelineName]; + if (timelineName == "color") { + var timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var color = valueMap["color"]; + var r = spine.SkeletonJson.toColor(color, 0); + var g = spine.SkeletonJson.toColor(color, 1); + var b = spine.SkeletonJson.toColor(color, 2); + var a = spine.SkeletonJson.toColor(color, 3); + timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); + + } else if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + + } else + throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; + } + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + } +}; +spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { + var curve = valueMap["curve"]; + if (!curve) return; + if (curve == "stepped") + timeline.curves.setStepped(frameIndex); + else if (curve instanceof Array) + timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); +}; +spine.SkeletonJson.toColor = function (hexString, colorIndex) { + if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; + return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; +}; + +spine.Atlas = function (atlasText, textureLoader) { + this.textureLoader = textureLoader; + this.pages = []; + this.regions = []; + + var reader = new spine.AtlasReader(atlasText); + var tuple = []; + tuple.length = 4; + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) break; + line = reader.trim(line); + if (line.length == 0) + page = null; + else if (!page) { + page = new spine.AtlasPage(); + page.name = line; + + page.format = spine.Atlas.Format[reader.readValue()]; + + reader.readTuple(tuple); + page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; + page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; + + var direction = reader.readValue(); + page.uWrap = spine.Atlas.TextureWrap.clampToEdge; + page.vWrap = spine.Atlas.TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "y") + page.vWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; + + textureLoader.load(page, line); + + this.pages.push(page); + + } else { + var region = new spine.AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + this.regions.push(region); + } + } +}; +spine.Atlas.prototype = { + findRegion: function (name) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + }, + dispose: function () { + var pages = this.pages; + for (var i = 0, n = pages.length; i < n; i++) + this.textureLoader.unload(pages[i].rendererObject); + }, + updateUVs: function (page) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) { + var region = regions[i]; + if (region.page != page) continue; + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.rotate) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + } + } +}; + +spine.Atlas.Format = { + alpha: 0, + intensity: 1, + luminanceAlpha: 2, + rgb565: 3, + rgba4444: 4, + rgb888: 5, + rgba8888: 6 +}; + +spine.Atlas.TextureFilter = { + nearest: 0, + linear: 1, + mipMap: 2, + mipMapNearestNearest: 3, + mipMapLinearNearest: 4, + mipMapNearestLinear: 5, + mipMapLinearLinear: 6 +}; + +spine.Atlas.TextureWrap = { + mirroredRepeat: 0, + clampToEdge: 1, + repeat: 2 +}; + +spine.AtlasPage = function () {}; +spine.AtlasPage.prototype = { + name: null, + format: null, + minFilter: null, + magFilter: null, + uWrap: null, + vWrap: null, + rendererObject: null, + width: 0, + height: 0 +}; + +spine.AtlasRegion = function () {}; +spine.AtlasRegion.prototype = { + page: null, + name: null, + x: 0, y: 0, + width: 0, height: 0, + u: 0, v: 0, u2: 0, v2: 0, + offsetX: 0, offsetY: 0, + originalWidth: 0, originalHeight: 0, + index: 0, + rotate: false, + splits: null, + pads: null, +}; + +spine.AtlasReader = function (text) { + this.lines = text.split(/\r\n|\r|\n/); +}; +spine.AtlasReader.prototype = { + index: 0, + trim: function (value) { + return value.replace(/^\s+|\s+$/g, ""); + }, + readLine: function () { + if (this.index >= this.lines.length) return null; + return this.lines[this.index++]; + }, + readValue: function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + return this.trim(line.substring(colon + 1)); + }, + /** Returns the number of tuple values read (2 or 4). */ + readTuple: function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + var i = 0, lastMatch= colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) { + if (i == 0) throw "Invalid line: " + line; + break; + } + tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = this.trim(line.substring(lastMatch)); + return i + 1; + } +} + +spine.AtlasAttachmentLoader = function (atlas) { + this.atlas = atlas; +} +spine.AtlasAttachmentLoader.prototype = { + newAttachment: function (skin, type, name) { + switch (type) { + case spine.AttachmentType.region: + var region = this.atlas.findRegion(name); + if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; + var attachment = new spine.RegionAttachment(name); + attachment.rendererObject = region; + attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + throw "Unknown attachment type: " + type; + } +} + +PIXI.AnimCache = {}; +spine.Bone.yDown = true; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * This object is one that will allow you to specify custom rendering functions based on render type + * + * @class CustomRenderable + * @extends DisplayObject + * @constructor + */ +PIXI.CustomRenderable = function() +{ + PIXI.DisplayObject.call( this ); + + this.renderable = true; +} + +// constructor +PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; + +/** + * If this object is being rendered by a CanvasRenderer it will call this callback + * + * @method renderCanvas + * @param renderer {CanvasRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback to initialize + * + * @method initWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.initWebGL = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback + * + * @method renderWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) +{ + // not sure if both needed? but ya have for now! + // override! +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.BaseTextureCache = {}; +PIXI.texturesToUpdate = []; +PIXI.texturesToDestroy = []; + +/** + * A texture stores the information that represents an image. All textures have a base texture + * + * @class BaseTexture + * @uses EventTarget + * @constructor + * @param source {String} the source object (image or canvas) + */ +PIXI.BaseTexture = function(source) +{ + PIXI.EventTarget.call( this ); + + /** + * [read-only] The width of the base texture set when the image has loaded + * + * @property width + * @type Number + * @readOnly + */ + this.width = 100; + + /** + * [read-only] The height of the base texture set when the image has loaded + * + * @property height + * @type Number + * @readOnly + */ + this.height = 100; + + /** + * [read-only] Describes if the base texture has loaded or not + * + * @property hasLoaded + * @type Boolean + * @readOnly + */ + this.hasLoaded = false; + + /** + * The source that is loaded to create the texture + * + * @property source + * @type Image + */ + this.source = source; + + if(!source)return; + + if(this.source instanceof Image || this.source instanceof HTMLImageElement) + { + if(this.source.complete) + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + else + { + + var scope = this; + this.source.onload = function(){ + + scope.hasLoaded = true; + scope.width = scope.source.width; + scope.height = scope.source.height; + + // add it to somewhere... + PIXI.texturesToUpdate.push(scope); + scope.dispatchEvent( { type: 'loaded', content: scope } ); + } + // this.image.src = imageUrl; + } + } + else + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + + this._powerOf2 = false; +} + +PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; + +/** + * Destroys this base texture + * + * @method destroy + */ +PIXI.BaseTexture.prototype.destroy = function() +{ + if(this.source instanceof Image) + { + this.source.src = null; + } + this.source = null; + PIXI.texturesToDestroy.push(this); +} + +/** + * Helper function that returns a base texture based on an image url + * If the image is not in the base texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @return BaseTexture + */ +PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) +{ + var baseTexture = PIXI.BaseTextureCache[imageUrl]; + if(!baseTexture) + { + // new Image() breaks tex loading in some versions of Chrome. + // See https://code.google.com/p/chromium/issues/detail?id=238071 + var image = new Image();//document.createElement('img'); + if (crossorigin) + { + image.crossOrigin = ''; + } + image.src = imageUrl; + baseTexture = new PIXI.BaseTexture(image); + PIXI.BaseTextureCache[imageUrl] = baseTexture; + } + + return baseTexture; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.TextureCache = {}; +PIXI.FrameCache = {}; + +/** + * A texture stores the information that represents an image or part of an image. It cannot be added + * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used + * + * @class Texture + * @uses EventTarget + * @constructor + * @param baseTexture {BaseTexture} The base texture source to create the texture from + * @param frame {Rectangle} The rectangle frame of the texture to show + */ +PIXI.Texture = function(baseTexture, frame) +{ + PIXI.EventTarget.call( this ); + + if(!frame) + { + this.noFrame = true; + frame = new PIXI.Rectangle(0,0,1,1); + } + + if(baseTexture instanceof PIXI.Texture) + baseTexture = baseTexture.baseTexture; + + /** + * The base texture of this texture + * + * @property baseTexture + * @type BaseTexture + */ + this.baseTexture = baseTexture; + + /** + * The frame specifies the region of the base texture that this texture uses + * + * @property frame + * @type Rectangle + */ + this.frame = frame; + + /** + * The trim point + * + * @property trim + * @type Point + */ + this.trim = new PIXI.Point(); + + this.scope = this; + + if(baseTexture.hasLoaded) + { + if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + //console.log(frame) + + this.setFrame(frame); + } + else + { + var scope = this; + baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); + } +} + +PIXI.Texture.prototype.constructor = PIXI.Texture; + +/** + * Called when the base texture is loaded + * + * @method onBaseTextureLoaded + * @param event + * @private + */ +PIXI.Texture.prototype.onBaseTextureLoaded = function(event) +{ + var baseTexture = this.baseTexture; + baseTexture.removeEventListener( 'loaded', this.onLoaded ); + + if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + this.noFrame = false; + this.width = this.frame.width; + this.height = this.frame.height; + + this.scope.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Destroys this texture + * + * @method destroy + * @param destroyBase {Boolean} Whether to destroy the base texture as well + */ +PIXI.Texture.prototype.destroy = function(destroyBase) +{ + if(destroyBase)this.baseTexture.destroy(); +} + +/** + * Specifies the rectangle region of the baseTexture + * + * @method setFrame + * @param frame {Rectangle} The frame of the texture to set it to + */ +PIXI.Texture.prototype.setFrame = function(frame) +{ + this.frame = frame; + this.width = frame.width; + this.height = frame.height; + + 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); + } + + this.updateFrame = true; + + PIXI.Texture.frameUpdates.push(this); + //this.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Helper function that returns a texture based on an image url + * If the image is not in the texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + * @return Texture + */ +PIXI.Texture.fromImage = function(imageUrl, crossorigin) +{ + var texture = PIXI.TextureCache[imageUrl]; + + if(!texture) + { + texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); + PIXI.TextureCache[imageUrl] = texture; + } + + return texture; +} + +/** + * Helper function that returns a texture based on a frame id + * If the frame id is not in the texture cache an error will be thrown + * + * @static + * @method fromFrame + * @param frameId {String} The frame id of the texture + * @return Texture + */ +PIXI.Texture.fromFrame = function(frameId) +{ + var texture = PIXI.TextureCache[frameId]; + if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); + return texture; +} + +/** + * Helper function that returns a texture based on a canvas element + * If the canvas is not in the texture cache it will be created and loaded + * + * @static + * @method fromCanvas + * @param canvas {Canvas} The canvas element source of the texture + * @return Texture + */ +PIXI.Texture.fromCanvas = function(canvas) +{ + var baseTexture = new PIXI.BaseTexture(canvas); + return new PIXI.Texture(baseTexture); +} + + +/** + * Adds a texture to the textureCache. + * + * @static + * @method addTextureToCache + * @param texture {Texture} + * @param id {String} the id that the texture will be stored against. + */ +PIXI.Texture.addTextureToCache = function(texture, id) +{ + PIXI.TextureCache[id] = texture; +} + +/** + * Remove a texture from the textureCache. + * + * @static + * @method removeTextureFromCache + * @param id {String} the id of the texture to be removed + * @return {Texture} the texture that was removed + */ +PIXI.Texture.removeTextureFromCache = function(id) +{ + var texture = PIXI.TextureCache[id] + PIXI.TextureCache[id] = null; + return texture; +} + +// this is more for webGL.. it contains updated frames.. +PIXI.Texture.frameUpdates = []; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. + + __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. + Otherwise black rectangles will be drawn instead. + + RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: + + var renderTexture = new PIXI.RenderTexture(800, 600); + var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); + sprite.position.x = 800/2; + sprite.position.y = 600/2; + sprite.anchor.x = 0.5; + sprite.anchor.y = 0.5; + renderTexture.render(sprite); + + Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: + + var doc = new PIXI.DisplayObjectContainer(); + doc.addChild(sprite); + renderTexture.render(doc); // Renders to center of renderTexture + + @class RenderTexture + @extends Texture + @constructor + @param width {Number} The width of the render texture + @param height {Number} The height of the render texture + */ +PIXI.RenderTexture = function(width, height) +{ + PIXI.EventTarget.call( this ); + + this.width = width || 100; + this.height = height || 100; + + this.indetityMatrix = PIXI.mat3.create(); + + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + if(PIXI.gl) + { + this.initWebGL(); + } + else + { + this.initCanvas(); + } +} + +PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); +PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; + +/** + * Initializes the webgl data for this texture + * + * @method initWebGL + * @private + */ +PIXI.RenderTexture.prototype.initWebGL = function() +{ + var gl = PIXI.gl; + this.glFramebuffer = gl.createFramebuffer(); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + this.glFramebuffer.width = this.width; + this.glFramebuffer.height = this.height; + + this.baseTexture = new PIXI.BaseTexture(); + + this.baseTexture.width = this.width; + this.baseTexture.height = this.height; + + this.baseTexture._glTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + this.baseTexture.isRender = true; + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); + + // create a projection matrix.. + this.projection = new PIXI.Point(this.width/2 , -this.height/2); + + // set the correct render function.. + this.render = this.renderWebGL; +} + + +PIXI.RenderTexture.prototype.resize = function(width, height) +{ + + this.width = width; + this.height = height; + + if(PIXI.gl) + { + this.projection.x = this.width/2 + this.projection.y = -this.height/2; + + var gl = PIXI.gl; + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + else + { + + this.frame.width = this.width + this.frame.height = this.height; + this.renderer.resize(this.width, this.height); + } +} + +/** + * Initializes the canvas data for this texture + * + * @method initCanvas + * @private + */ +PIXI.RenderTexture.prototype.initCanvas = function() +{ + this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); + + this.baseTexture = new PIXI.BaseTexture(this.renderer.view); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + this.render = this.renderCanvas; +} + +/** + * This function will draw the display object to the texture. + * + * @method renderWebGL + * @param displayObject {DisplayObject} The display object to render this texture on + * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn + * @private + */ +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +{ + var gl = PIXI.gl; + + // enable the alpha color mask.. + gl.colorMask(true, true, true, true); + + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + if(clear) + { + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + // THIS WILL MESS WITH HIT TESTING! + var children = displayObject.children; + + //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; + displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; + // modify to flip... + displayObject.worldTransform[4] = -1; + displayObject.worldTransform[5] = this.projection.y * -2; + + if(position) + { + displayObject.worldTransform[2] = position.x; + displayObject.worldTransform[5] -= position.y; + } + + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + + for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded + * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported + * sprite sheet data formats only include "JSON" at this time. Supported bitmap font + * data formats include "xml" and "fnt". + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.AssetLoader = function(assetURLs, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The array of asset URLs that are going to be loaded + * + * @property assetURLs + * @type Array + */ + this.assetURLs = assetURLs; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * Maps file extension to loader types + * + * @property loadersByType + * @type Object + */ + this.loadersByType = { + "jpg": PIXI.ImageLoader, + "jpeg": PIXI.ImageLoader, + "png": PIXI.ImageLoader, + "gif": PIXI.ImageLoader, + "json": PIXI.JsonLoader, + "anim": PIXI.SpineLoader, + "xml": PIXI.BitmapFontLoader, + "fnt": PIXI.BitmapFontLoader + }; + + +}; + +/** + * Fired when an item has loaded + * @event onProgress + */ + +/** + * Fired when all the assets have loaded + * @event onComplete + */ + +// constructor +PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; + +/** + * Starts loading the assets sequentially + * + * @method load + */ +PIXI.AssetLoader.prototype.load = function() +{ + var scope = this; + + this.loadCount = this.assetURLs.length; + + for (var i=0; i < this.assetURLs.length; i++) + { + var fileName = this.assetURLs[i]; + var fileType = fileName.split("?").shift().split(".").pop().toLowerCase(); + + var loaderClass = this.loadersByType[fileType]; + if(!loaderClass) + throw new Error(fileType + " is an unsupported file type"); + + var loader = new loaderClass(fileName, this.crossorigin); + + loader.addEventListener("loaded", function() + { + scope.onAssetLoaded(); + }); + loader.load(); + } +}; + +/** + * Invoked after each file is loaded + * + * @method onAssetLoaded + * @private + */ +PIXI.AssetLoader.prototype.onAssetLoaded = function() +{ + this.loadCount--; + this.dispatchEvent({type: "onProgress", content: this}); + if(this.onProgress) this.onProgress(); + + if(this.loadCount == 0) + { + this.dispatchEvent({type: "onComplete", content: this}); + if(this.onComplete) this.onComplete(); + } +}; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The json file loader is used to load in JSON data and parsing it + * When loaded this class will dispatch a "loaded" event + * If load failed this class will dispatch a "error" event + * + * @class JsonLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.JsonLoader = function (url, crossorigin) { + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * [read-only] Whether the data has loaded yet + * + * @property loaded + * @type Boolean + * @readOnly + */ + this.loaded = false; + +}; + +// constructor +PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; + +/** + * Loads the JSON data + * + * @method load + */ +PIXI.JsonLoader.prototype.load = function () { + this.ajaxRequest = new AjaxRequest(); + var scope = this; + this.ajaxRequest.onreadystatechange = function () { + scope.onJSONLoaded(); + }; + + this.ajaxRequest.open("GET", this.url, true); + if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); + this.ajaxRequest.send(null); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.JsonLoader.prototype.onJSONLoaded = function () { + if (this.ajaxRequest.readyState == 4) { + if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { + this.json = JSON.parse(this.ajaxRequest.responseText); + + if(this.json.frames) + { + // sprite sheet + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); + + } + else if(this.json.bones) + { + // spine animation + var spineJsonParser = new spine.SkeletonJson(); + var skeletonData = spineJsonParser.readSkeletonData(this.json); + PIXI.AnimCache[this.url] = skeletonData; + this.onLoaded(); + } + else + { + this.onLoaded(); + } + } + else + { + this.onError(); + } + } +}; + +/** + * Invoke when json file loaded + * + * @method onLoaded + * @private + */ +PIXI.JsonLoader.prototype.onLoaded = function () { + this.loaded = true; + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * Invoke when error occured + * + * @method onError + * @private + */ +PIXI.JsonLoader.prototype.onError = function () { + this.dispatchEvent({ + type: "error", + content: this + }); +}; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The sprite sheet loader is used to load in JSON sprite sheet data + * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format + * There is a free version so thats nice, although the paid version is great value for money. + * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. + * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * This loader will also load the image file that the Spritesheet points to as well as the data. + * When loaded this class will dispatch a "loaded" event + * + * @class SpriteSheetLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the sprite sheet JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ + +PIXI.SpriteSheetLoader = function (url, crossorigin) { + /* + * i use texture packer to load the assets.. + * http://www.codeandweb.com/texturepacker + * make sure to set the format as "JSON" + */ + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = null; + + /** + * The frames of the sprite sheet + * + * @property frames + * @type Object + */ + this.frames = {}; +}; + +// constructor +PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; + +/** + * This will begin loading the JSON file + * + * @method load + */ +PIXI.SpriteSheetLoader.prototype.load = function () { + var scope = this; + var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); + jsonLoader.addEventListener("loaded", function (event) { + scope.json = event.content.json; + scope.onJSONLoaded(); + }); + jsonLoader.load(); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); +}; +/** + * Invoke when all files are loaded (json and texture) + * + * @method onLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onLoaded = function () { + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") + * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * When loaded this class will dispatch a 'loaded' event + * + * @class ImageLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the image + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.ImageLoader = function(url, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = PIXI.Texture.fromImage(url, crossorigin); + + /** + * if the image is loaded with loadFramedSpriteSheet + * frames will contain the sprite sheet frames + * + */ + this.frames = []; +}; + +// constructor +PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; + +/** + * Loads image or takes it from cache + * + * @method load + */ +PIXI.ImageLoader.prototype.load = function() +{ + if(!this.texture.baseTexture.hasLoaded) + { + var scope = this; + this.texture.baseTexture.addEventListener("loaded", function() + { + scope.onLoaded(); + }); + } + else + { + this.onLoaded(); + } +}; + +/** + * Invoked when image file is loaded or it is already cached and ready to use + * + * @method onLoaded + * @private + */ +PIXI.ImageLoader.prototype.onLoaded = function() +{ + this.dispatchEvent({type: "loaded", content: this}); +}; + +/** + * Loads image and split it to uniform sized frames + * + * + * @method loadFramedSpriteSheet + * @param frameWidth {Number} with of each frame + * @param frameHeight {Number} height of each frame + * @param textureName {String} if given, the frames will be cached in - format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', - '<%= dirs.src %>/filters/GreyFilter.js', + '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', '<%= dirs.src %>/filters/PixelateFilter.js', '<%= dirs.src %>/filters/BlurXFilter.js', diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index 21b0257..1e11684 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1,12289 +1,12548 @@ /** + * @license + * Pixi.JS - v1.3.0 + * Copyright (c) 2012, Mat Groves + * http://goodboydigital.com/ + * + * Compiled: 2013-11-20 + * + * Pixi.JS is licensed under the MIT License. + * http://www.opensource.org/licenses/mit-license.php + */ +/** * @author Mat Groves http://matgroves.com/ @Doormat23 */ (function(){ var root = this; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * @module PIXI - */ -var PIXI = PIXI || {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point - * @param y {Number} position of the point - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -} - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -} - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -} - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - - -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -} - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -} - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; - -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayobjects - * - * @class Circle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -} - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -} - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - - -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayobjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall width of this ellipse - * @param height {Number} The overall height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - //and a radius of 0.5 - var normx = ((x - this.x) / this.width) - 0.5, - normy = ((y - this.y) / this.height) - 0.5; - - normx *= normx; - normy *= normy; - - return (normx + normy < 0.25); -} - -PIXI.Ellipse.getBounds = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - - - -/* - * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV - * you both rock! - */ - -function determineMatrixArrayType() { - PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; - return PIXI.Matrix; -} - -determineMatrixArrayType(); - -PIXI.mat3 = {}; - -PIXI.mat3.create = function() -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat3.identity = function(matrix) -{ - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat4 = {}; - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat3.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], - a10 = mat[3], a11 = mat[4], a12 = mat[5], - a20 = mat[6], a21 = mat[7], a22 = mat[8], - - b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], - b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], - b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - - dest[0] = b00 * a00 + b01 * a10 + b02 * a20; - dest[1] = b00 * a01 + b01 * a11 + b02 * a21; - dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - - dest[3] = b10 * a00 + b11 * a10 + b12 * a20; - dest[4] = b10 * a01 + b11 * a11 + b12 * a21; - dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - - dest[6] = b20 * a00 + b21 * a10 + b22 * a20; - dest[7] = b20 * a01 + b21 * a11 + b22 * a21; - dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - - return dest; -} - -PIXI.mat3.clone = function(mat) -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = mat[0]; - matrix[1] = mat[1]; - matrix[2] = mat[2]; - matrix[3] = mat[3]; - matrix[4] = mat[4]; - matrix[5] = mat[5]; - matrix[6] = mat[6]; - matrix[7] = mat[7]; - matrix[8] = mat[8]; - - return matrix; -} - -PIXI.mat3.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) { - var a01 = mat[1], a02 = mat[2], - a12 = mat[5]; - - mat[1] = mat[3]; - mat[2] = mat[6]; - mat[3] = a01; - mat[5] = mat[7]; - mat[6] = a02; - mat[7] = a12; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[3]; - dest[2] = mat[6]; - dest[3] = mat[1]; - dest[4] = mat[4]; - dest[5] = mat[7]; - dest[6] = mat[2]; - dest[7] = mat[5]; - dest[8] = mat[8]; - return dest; -} - -PIXI.mat3.toMat4 = function (mat, dest) -{ - if (!dest) { dest = PIXI.mat4.create(); } - - dest[15] = 1; - dest[14] = 0; - dest[13] = 0; - dest[12] = 0; - - dest[11] = 0; - dest[10] = mat[8]; - dest[9] = mat[7]; - dest[8] = mat[6]; - - dest[7] = 0; - dest[6] = mat[5]; - dest[5] = mat[4]; - dest[4] = mat[3]; - - dest[3] = 0; - dest[2] = mat[2]; - dest[1] = mat[1]; - dest[0] = mat[0]; - - return dest; -} - - -///// - - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat4.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) - { - var a01 = mat[1], a02 = mat[2], a03 = mat[3], - a12 = mat[6], a13 = mat[7], - a23 = mat[11]; - - mat[1] = mat[4]; - mat[2] = mat[8]; - mat[3] = mat[12]; - mat[4] = a01; - mat[6] = mat[9]; - mat[7] = mat[13]; - mat[8] = a02; - mat[9] = a12; - mat[11] = mat[14]; - mat[12] = a03; - mat[13] = a13; - mat[14] = a23; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[4]; - dest[2] = mat[8]; - dest[3] = mat[12]; - dest[4] = mat[1]; - dest[5] = mat[5]; - dest[6] = mat[9]; - dest[7] = mat[13]; - dest[8] = mat[2]; - dest[9] = mat[6]; - dest[10] = mat[10]; - dest[11] = mat[14]; - dest[12] = mat[3]; - dest[13] = mat[7]; - dest[14] = mat[11]; - dest[15] = mat[15]; - return dest; -} - -PIXI.mat4.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; - var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; - var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; - var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - - // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; - dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[4]; - b1 = mat2[5]; - b2 = mat2[6]; - b3 = mat2[7]; - dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[8]; - b1 = mat2[9]; - b2 = mat2[10]; - b3 = mat2[11]; - dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[12]; - b1 = mat2[13]; - b2 = mat2[14]; - b3 = mat2[15]; - dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - return dest; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The base class for all objects that are rendered on the screen. - * - * @class DisplayObject - * @constructor - */ -PIXI.DisplayObject = function() -{ - this.last = this; - this.first = this; - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @property position - * @type Point - */ - this.position = new PIXI.Point(); - - /** - * The scale factor of the object. - * - * @property scale - * @type Point - */ - this.scale = new PIXI.Point(1,1);//{x:1, y:1}; - - /** - * The pivot point of the displayObject that it rotates around - * - * @property pivot - * @type Point - */ - this.pivot = new PIXI.Point(0,0); - - /** - * The rotation of the object in radians. - * - * @property rotation - * @type Number - */ - this.rotation = 0; - - /** - * The opacity of the object. - * - * @property alpha - * @type Number - */ - this.alpha = 1; - - /** - * The visibility of the object. - * - * @property visible - * @type Boolean - */ - this.visible = true; - - /** - * This is the defined area that will pick up mouse / touch events. It is null by default. - * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) - * - * @property hitArea - * @type Rectangle|Circle|Ellipse|Polygon - */ - this.hitArea = null; - - /** - * This is used to indicate if the displayObject should display a mouse hand cursor on rollover - * - * @property buttonMode - * @type Boolean - */ - this.buttonMode = false; - - /** - * Can this object be rendered - * - * @property renderable - * @type Boolean - */ - this.renderable = false; - - /** - * [read-only] The display object container that contains this display object. - * - * @property parent - * @type DisplayObjectContainer - * @readOnly - */ - this.parent = null; - - /** - * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. - * - * @property stage - * @type Stage - * @readOnly - */ - this.stage = null; - - /** - * [read-only] The multiplied alpha of the displayobject - * - * @property worldAlpha - * @type Number - * @readOnly - */ - this.worldAlpha = 1; - - /** - * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property - * - * @property _interactive - * @type Boolean - * @readOnly - * @private - */ - this._interactive = false; - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [read-only] Current transform of the object locally - * - * @property localTransform - * @type Mat3 - * @readOnly - * @private - */ - this.localTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [NYI] Unkown - * - * @property color - * @type Array<> - * @private - */ - this.color = []; - - /** - * [NYI] Holds whether or not this object is dynamic, for rendering optimization - * - * @property dynamic - * @type Boolean - * @private - */ - this.dynamic = true; - - // chach that puppy! - this._sr = 0; - this._cr = 1; - - - this.filterArea = new PIXI.Rectangle(0,0,1,1); - - /* - * MOUSE Callbacks - */ - - /** - * A callback that is used when the users clicks on the displayObject with their mouse - * @method click - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user clicks the mouse down over the sprite - * @method mousedown - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject - * for this callback to be fired the mouse must have been pressed down over the displayObject - * @method mouseup - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject - * for this callback to be fired, The touch must have started over the displayObject - * @method mouseupoutside - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse rolls over the displayObject - * @method mouseover - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse leaves the displayObject - * @method mouseout - * @param interactionData {InteractionData} - */ - - - /* - * TOUCH Callbacks - */ - - /** - * A callback that is used when the users taps on the sprite with their finger - * basically a touch version of click - * @method tap - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user touch's over the displayObject - * @method touchstart - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases a touch over the displayObject - * @method touchend - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the touch that was over the displayObject - * for this callback to be fired, The touch must have started over the sprite - * @method touchendoutside - * @param interactionData {InteractionData} - */ -} - -// constructor -PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; - -/** - * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default - * Instead of using this function you can now simply set the interactive property to true or false - * - * @method setInteractive - * @param interactive {Boolean} - * @deprecated Simply set the `interactive` property directly - */ -PIXI.DisplayObject.prototype.setInteractive = function(interactive) -{ - this.interactive = interactive; -} - -/** - * Indicates if the sprite will have touch and mouse interactivity. It is false by default - * - * @property interactive - * @type Boolean - * @default false - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { - get: function() { - return this._interactive; - }, - set: function(value) { - this._interactive = value; - - // TODO more to be done here.. - // need to sort out a re-crawl! - if(this.stage)this.stage.dirty = true; - } -}); - -/** - * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. - * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. - * To remove a mask, set this property to null. - * - * @property mask - * @type Graphics - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { - get: function() { - return this._mask; - }, - set: function(value) { - - - if(value) - { - if(this._mask) - { - value.start = this._mask.start; - value.end = this._mask.end; - } - else - { - this.addFilter(value); - value.renderable = false; - } - } - else - { - this.removeFilter(this._mask); - this._mask.renderable = true; - } - - this._mask = value; - } -}); - -/** - * Sets the filters for the displayObject. - * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. - * To remove filters simply set this property to 'null' - * @property filters - * @type Array An array of filters - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { - get: function() { - return this._filters; - }, - set: function(value) { - - if(value) - { - if(this._filters)this.removeFilter(this._filters); - this.addFilter(value); - - // now put all the passes in one place.. - var passes = []; - for (var i = 0; i < value.length; i++) - { - var filterPasses = value[i].passes; - for (var j = 0; j < filterPasses.length; j++) - { - passes.push(filterPasses[j]); - }; - }; - - value.start.filterPasses = passes; - } - else - { - if(this._filters)this.removeFilter(this._filters); - } - - this._filters = value; - - - - - } -}); - -/* - * Adds a filter to this displayObject - * - * @method addFilter - * @param mask {Graphics} the graphics object to use as a filter - * @private - */ -PIXI.DisplayObject.prototype.addFilter = function(data) -{ - //if(this.filter)return; - //this.filter = true; -// data[0].target = this; - - - // insert a filter block.. - // TODO Onject pool thease bad boys.. - var start = new PIXI.FilterBlock(); - var end = new PIXI.FilterBlock(); - - data.start = start; - data.end = end; - - start.data = data; - end.data = data; - - start.first = start.last = this; - end.first = end.last = this; - - start.open = true; - - start.target = this; - - /* - * insert start - */ - - var childFirst = start - var childLast = start - var nextObject; - var previousObject; - - previousObject = this.first._iPrev; - - if(previousObject) - { - nextObject = previousObject._iNext; - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - } - else - { - nextObject = this; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - - // now insert the end filter block.. - - /* - * insert end filter - */ - var childFirst = end - var childLast = end - var nextObject = null; - var previousObject = null; - - previousObject = this.last; - nextObject = previousObject._iNext; - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - var updateLast = this; - - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = end; - } - updateLast = updateLast.parent; - } - - this.first = start; - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.addFilterBlocks(start, end); - } - -} - -/* - * Removes the filter to this displayObject - * - * @method removeFilter - * @private - */ -PIXI.DisplayObject.prototype.removeFilter = function(data) -{ - //if(!this.filter)return; - //this.filter = false; - console.log("YUOIO") - // modify the list.. - var startBlock = data.start; - - - var nextObject = startBlock._iNext; - var previousObject = startBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - if(previousObject)previousObject._iNext = nextObject; - - this.first = startBlock._iNext; - - // remove the end filter - var lastBlock = data.end; - - var nextObject = lastBlock._iNext; - var previousObject = lastBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - // this is always true too! - var tempLast = lastBlock._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == lastBlock) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); - } -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObject.prototype.updateTransform = function() -{ - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); - } - - var localTransform = this.localTransform; - var parentTransform = this.parent.worldTransform; - var worldTransform = this.worldTransform; - //console.log(localTransform) - localTransform[0] = this._cr * this.scale.x; - localTransform[1] = -this._sr * this.scale.y - localTransform[3] = this._sr * this.scale.x; - localTransform[4] = this._cr * this.scale.y; - - // TODO --> do we even need a local matrix??? - - var px = this.pivot.x; - var py = this.pivot.y; - - // Cache the matrix values (makes for huge speed increases!) - var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], - a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], - - b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], - b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; - - localTransform[2] = a02 - localTransform[5] = a12 - - worldTransform[0] = b00 * a00 + b01 * a10; - worldTransform[1] = b00 * a01 + b01 * a11; - worldTransform[2] = b00 * a02 + b01 * a12 + b02; - - worldTransform[3] = b10 * a00 + b11 * a10; - worldTransform[4] = b10 * a01 + b11 * a11; - worldTransform[5] = b10 * a02 + b11 * a12 + b12; - - // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! - // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); - this.worldAlpha = this.alpha * this.parent.worldAlpha; - - this.vcount = PIXI.visibleCount; - -} - -PIXI.visibleCount = 0; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A DisplayObjectContainer represents a collection of display objects. - * It is the base class of all display objects that act as a container for other objects. - * - * @class DisplayObjectContainer - * @extends DisplayObject - * @constructor - */ -PIXI.DisplayObjectContainer = function() -{ - PIXI.DisplayObject.call( this ); - - /** - * [read-only] The of children of this container. - * - * @property children - * @type Array - * @readOnly - */ - this.children = []; -} - -// constructor -PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; - -/** - * Adds a child to the container. - * - * @method addChild - * @param child {DisplayObject} The DisplayObject to add to the container - */ -PIXI.DisplayObjectContainer.prototype.addChild = function(child) -{ - if(child.parent != undefined) - { - - //// COULD BE THIS??? - child.parent.removeChild(child); - // return; - } - - child.parent = this; - - this.children.push(child); - - // update the stage refference.. - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // LINKED LIST // - - // modify the list.. - var childFirst = child.first - var childLast = child.last; - var nextObject; - var previousObject; - - // this could be wrong if there is a filter?? - if(this._filters || this._mask) - { - previousObject = this.last._iPrev; - } - else - { - previousObject = this.last; - } - - nextObject = previousObject._iNext; - - // always true in this case - // need to make sure the parents last is updated too - var updateLast = this; - var prevLast = previousObject; - - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - -} - -/** - * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown - * - * @method addChildAt - * @param child {DisplayObject} The child to add - * @param index {Number} The index to place the child in - */ -PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) -{ - if(index >= 0 && index <= this.children.length) - { - if(child.parent != undefined) - { - child.parent.removeChild(child); - } - child.parent = this; - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - var nextObject; - var previousObject; - - if(index == this.children.length) - { - previousObject = this.last; - var updateLast = this; - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - } - else if(index == 0) - { - previousObject = this; - } - else - { - previousObject = this.children[index-1].last; - } - - nextObject = previousObject._iNext; - - // always true in this case - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - this.children.splice(index, 0, child); - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - - } - else - { - throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); - } -} - -/** - * [NYI] Swaps the depth of 2 displayObjects - * - * @method swapChildren - * @param child {DisplayObject} - * @param child2 {DisplayObject} - * @private - */ -PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) -{ - /* - * this funtion needs to be recoded.. - * can be done a lot faster.. - */ - return; - - // need to fix this function :/ - /* - // TODO I already know this?? - var index = this.children.indexOf( child ); - var index2 = this.children.indexOf( child2 ); - - if ( index !== -1 && index2 !== -1 ) - { - // cool - - /* - if(this.stage) - { - // this is to satisfy the webGL batching.. - // TODO sure there is a nicer way to achieve this! - this.stage.__removeChild(child); - this.stage.__removeChild(child2); - - this.stage.__addChild(child); - this.stage.__addChild(child2); - } - - // swap the positions.. - this.children[index] = child2; - this.children[index2] = child; - - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - }*/ -} - -/** - * Returns the Child at the specified index - * - * @method getChildAt - * @param index {Number} The index to get the child from - */ -PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) -{ - if(index >= 0 && index < this.children.length) - { - return this.children[index]; - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - } -} - -/** - * Removes a child from the container. - * - * @method removeChild - * @param child {DisplayObject} The DisplayObject to remove - */ -PIXI.DisplayObjectContainer.prototype.removeChild = function(child) -{ - var index = this.children.indexOf( child ); - if ( index !== -1 ) - { - // unlink // - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - - var nextObject = childLast._iNext; - var previousObject = childFirst._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - if(this.last == childLast) - { - var tempLast = childFirst._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == childLast.last) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - } - - childLast._iNext = null; - childFirst._iPrev = null; - - // update the stage reference.. - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = null; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // webGL trim - if(child.__renderGroup) - { - child.__renderGroup.removeDisplayObjectAndChildren(child); - } - - child.parent = undefined; - this.children.splice( index, 1 ); - } - else - { - throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); - } -} - -/* - * Updates the container's children's transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObjectContainer.prototype.updateTransform = function() -{ - if(!this.visible)return; - - PIXI.DisplayObject.prototype.updateTransform.call( this ); - - for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation - */ -PIXI.MovieClip = function(textures) -{ - PIXI.Sprite.call(this, textures[0]); - - /** - * The array of textures that make up the animation - * - * @property textures - * @type Array - */ - this.textures = textures; - - /** - * The speed that the MovieClip will play at. Higher is faster, lower is slower - * - * @property animationSpeed - * @type Number - * @default 1 - */ - this.animationSpeed = 1; - - /** - * Whether or not the movie clip repeats after playing. - * - * @property loop - * @type Boolean - * @default true - */ - this.loop = true; - - /** - * Function to call when a MovieClip finishes playing - * - * @property onComplete - * @type Function - */ - this.onComplete = null; - - /** - * [read-only] The index MovieClips current frame (this may not have to be a whole number) - * - * @property currentFrame - * @type Number - * @default 0 - * @readOnly - */ - this.currentFrame = 0; - - /** - * [read-only] Indicates if the MovieClip is currently playing - * - * @property playing - * @type Boolean - * @readOnly - */ - this.playing = false; -} - -// constructor -PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); -PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; - -/** -* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures -* assigned to the MovieClip. -* -* @property totalFrames -* @type Number -* @default 0 -* @readOnly -*/ -Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { - get: function() { - - return this.textures.length; - } -}); - - -/** - * Stops the MovieClip - * - * @method stop - */ -PIXI.MovieClip.prototype.stop = function() -{ - this.playing = false; -} - -/** - * Plays the MovieClip - * - * @method play - */ -PIXI.MovieClip.prototype.play = function() -{ - this.playing = true; -} - -/** - * Stops the MovieClip and goes to a specific frame - * - * @method gotoAndStop - * @param frameNumber {Number} frame index to stop at - */ -PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) -{ - this.playing = false; - this.currentFrame = frameNumber; - var round = (this.currentFrame + 0.5) | 0; - this.setTexture(this.textures[round % this.textures.length]); -} - -/** - * Goes to a specific frame and begins playing the MovieClip - * - * @method gotoAndPlay - * @param frameNumber {Number} frame index to start at - */ -PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) -{ - this.currentFrame = frameNumber; - this.playing = true; -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.MovieClip.prototype.updateTransform = function() -{ - PIXI.Sprite.prototype.updateTransform.call(this); - - if(!this.playing)return; - - this.currentFrame += this.animationSpeed; - - var round = (this.currentFrame + 0.5) | 0; - - if(this.loop || round < this.textures.length) - { - this.setTexture(this.textures[round % this.textures.length]); - } - else if(round >= this.textures.length) - { - this.gotoAndStop(this.textures.length - 1); - if(this.onComplete) - { - this.onComplete(); - } - } -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - - -PIXI.FilterBlock = function() -{ - this.visible = true; - this.renderable = true; -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text to split a line you can use "\n" - * - * @class Text - * @extends Sprite - * @constructor - * @param text {String} The copy that you would like the text to display - * @param [style] {Object} The style parameters - * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text = function(text, style) -{ - this.canvas = document.createElement("canvas"); - this.context = this.canvas.getContext("2d"); - PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); - - this.setText(text); - this.setStyle(style); - - this.updateText(); - this.dirty = false; -}; - -// constructor -PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); -PIXI.Text.prototype.constructor = PIXI.Text; - -/** - * Set the style of the text - * - * @method setStyle - * @param [style] {Object} The style parameters - * @param [style.font="bold 20pt Arial"] {String} The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text.prototype.setStyle = function(style) -{ - style = style || {}; - style.font = style.font || "bold 20pt Arial"; - style.fill = style.fill || "black"; - style.align = style.align || "left"; - style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 - style.strokeThickness = style.strokeThickness || 0; - style.wordWrap = style.wordWrap || false; - style.wordWrapWidth = style.wordWrapWidth || 100; - this.style = style; - this.dirty = true; -}; - -/** - * Set the copy for the text object. To split a line you can use "\n" - * - * @methos setText - * @param {String} text The copy that you would like the text to display - */ -PIXI.Text.prototype.setText = function(text) -{ - this.text = text.toString() || " "; - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.Text.prototype.updateText = function() -{ - this.context.font = this.style.font; - - var outputText = this.text; - - // word wrap - // preserve original text - if(this.style.wordWrap)outputText = this.wordWrap(this.text); - - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - //calculate text width - var lineWidths = []; - var maxLineWidth = 0; - for (var i = 0; i < lines.length; i++) - { - var lineWidth = this.context.measureText(lines[i]).width; - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - this.canvas.width = maxLineWidth + this.style.strokeThickness; - - //calculate text height - var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; - this.canvas.height = lineHeight * lines.length; - - //set canvas text styles - this.context.fillStyle = this.style.fill; - this.context.font = this.style.font; - - this.context.strokeStyle = this.style.stroke; - this.context.lineWidth = this.style.strokeThickness; - - this.context.textBaseline = "top"; - - //draw lines line by line - for (i = 0; i < lines.length; i++) - { - var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - - if(this.style.align == "right") - { - linePosition.x += maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - linePosition.x += (maxLineWidth - lineWidths[i]) / 2; - } - - if(this.style.stroke && this.style.strokeThickness) - { - this.context.strokeText(lines[i], linePosition.x, linePosition.y); - } - - if(this.style.fill) - { - this.context.fillText(lines[i], linePosition.x, linePosition.y); - } - } - - this.updateTexture(); -}; - -/** - * Updates texture size based on canvas size - * - * @method updateTexture - * @private - */ -PIXI.Text.prototype.updateTexture = function() -{ - this.texture.baseTexture.width = this.canvas.width; - this.texture.baseTexture.height = this.canvas.height; - this.texture.frame.width = this.canvas.width; - this.texture.frame.height = this.canvas.height; - - this._width = this.canvas.width; - this._height = this.canvas.height; - - PIXI.texturesToUpdate.push(this.texture.baseTexture); -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.Text.prototype.updateTransform = function() -{ - if(this.dirty) - { - this.updateText(); - this.dirty = false; - } - - PIXI.Sprite.prototype.updateTransform.call(this); -}; - -/* - * http://stackoverflow.com/users/34441/ellisbben - * great solution to the problem! - * - * @method determineFontHeight - * @param fontStyle {Object} - * @private - */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) -{ - // build a little reference dictionary so if the font style has been used return a - // cached version... - var result = PIXI.Text.heightCache[fontStyle]; - - if(!result) - { - var body = document.getElementsByTagName("body")[0]; - var dummy = document.createElement("div"); - var dummyText = document.createTextNode("M"); - dummy.appendChild(dummyText); - dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); - body.appendChild(dummy); - - result = dummy.offsetHeight; - PIXI.Text.heightCache[fontStyle] = result; - - body.removeChild(dummy); - } - - return result; -}; - -/** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. - * - * @method wordWrap - * @param text {String} - * @private - */ -PIXI.Text.prototype.wordWrap = function(text) -{ - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ""; - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) - { - var spaceLeft = this.style.wordWrapWidth; - var words = lines[i].split(" "); - for (var j = 0; j < words.length; j++) - { - var wordWidth = this.context.measureText(words[j]).width; - var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; - if(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 = this.style.wordWrapWidth - wordWidth; - } - else - { - spaceLeft -= wordWidthWithSpace; - result += words[j] + " "; - } - } - result += "\n"; - } - return result; -}; - -/** - * Destroys this text object - * - * @method destroy - * @param destroyTexture {Boolean} - */ -PIXI.Text.prototype.destroy = function(destroyTexture) -{ - if(destroyTexture) - { - this.texture.destroy(); - } - -}; - -PIXI.Text.heightCache = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using - * http://www.angelcode.com/products/bmfont/ for windows or - * http://www.bmglyph.com/ for mac. - * - * @class BitmapText - * @extends DisplayObjectContainer - * @constructor - * @param text {String} The copy that you would like the text to display - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText = function(text, style) -{ - PIXI.DisplayObjectContainer.call(this); - - this.setText(text); - this.setStyle(style); - this.updateText(); - this.dirty = false - -}; - -// constructor -PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; - -/** - * Set the copy for the text object - * - * @method setText - * @param text {String} The copy that you would like the text to display - */ -PIXI.BitmapText.prototype.setText = function(text) -{ - this.text = text || " "; - this.dirty = true; -}; - -/** - * Set the style of the text - * - * @method setStyle - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText.prototype.setStyle = function(style) -{ - style = style || {}; - style.align = style.align || "left"; - this.style = style; - - var font = style.font.split(" "); - this.fontName = font[font.length - 1]; - this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; - - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.BitmapText.prototype.updateText = function() -{ - var data = PIXI.BitmapText.fonts[this.fontName]; - var pos = new PIXI.Point(); - var prevCharCode = null; - var chars = []; - var maxLineWidth = 0; - var lineWidths = []; - var line = 0; - var scale = this.fontSize / data.size; - for(var i = 0; i < this.text.length; i++) - { - var charCode = this.text.charCodeAt(i); - if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) - { - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - line++; - - pos.x = 0; - pos.y += data.lineHeight; - prevCharCode = null; - continue; - } - - var charData = data.chars[charCode]; - if(!charData) continue; - - if(prevCharCode && charData[prevCharCode]) - { - pos.x += charData.kerning[prevCharCode]; - } - chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); - pos.x += charData.xAdvance; - - prevCharCode = charCode; - } - - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - - var lineAlignOffsets = []; - for(i = 0; i <= line; i++) - { - var alignOffset = 0; - if(this.style.align == "right") - { - alignOffset = maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - alignOffset = (maxLineWidth - lineWidths[i]) / 2; - } - lineAlignOffsets.push(alignOffset); - } - - for(i = 0; i < chars.length; i++) - { - var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); - c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; - c.position.y = chars[i].position.y * scale; - c.scale.x = c.scale.y = scale; - this.addChild(c); - } - - this.width = pos.x * scale; - this.height = (pos.y + data.lineHeight) * scale; -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.BitmapText.prototype.updateTransform = function() -{ - if(this.dirty) - { - while(this.children.length > 0) - { - this.removeChild(this.getChildAt(0)); - } - this.updateText(); - - this.dirty = false; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - -PIXI.BitmapText.fonts = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - /** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive - * This manager also supports multitouch. - * - * @class InteractionManager - * @constructor - * @param stage {Stage} The stage to handle interactions - */ -PIXI.InteractionManager = function(stage) -{ - /** - * a refference to the stage - * - * @property stage - * @type Stage - */ - this.stage = stage; - - /** - * the mouse data - * - * @property mouse - * @type InteractionData - */ - this.mouse = new PIXI.InteractionData(); - - /** - * an object that stores current touches (InteractionData) by id reference - * - * @property touchs - * @type Object - */ - this.touchs = {}; - - - - // helpers - this.tempPoint = new PIXI.Point(); - //this.tempMatrix = mat3.create(); - - this.mouseoverEnabled = true; - - //tiny little interactiveData pool! - this.pool = []; - - this.interactiveItems = []; - this.interactionDOMElement = null; - - //this will make it so that you dont have to call bind all the time - this.onMouseMove = this.onMouseMove.bind( this ); - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseOut = this.onMouseOut.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - - this.onTouchStart = this.onTouchStart.bind(this); - this.onTouchEnd = this.onTouchEnd.bind(this); - this.onTouchMove = this.onTouchMove.bind(this); - - - this.last = 0; -} - -// constructor -PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; - -/** - * Collects an interactive sprite recursively to have their interactions managed - * - * @method collectInteractiveSprite - * @param displayObject {DisplayObject} the displayObject to collect - * @param iParent {DisplayObject} - * @private - */ -PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) -{ - var children = displayObject.children; - var length = children.length; - - /// make an interaction tree... {item.__interactiveParent} - for (var i = length-1; i >= 0; i--) - { - var child = children[i]; - -// if(child.visible) { - // push all interactive bits - if(child.interactive) - { - iParent.interactiveChildren = true; - //child.__iParent = iParent; - this.interactiveItems.push(child); - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, child); - } - } - else - { - child.__iParent = null; - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, iParent); - } - } -// } - } -} - -/** - * Sets the target for event delegation - * - * @method setTarget - * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to - * @private - */ -PIXI.InteractionManager.prototype.setTarget = function(target) -{ - this.target = target; - - //check if the dom element has been set. If it has don't do anything - if( this.interactionDOMElement === null ) { - - this.setTargetDomElement( target.view ); - } - - document.body.addEventListener('mouseup', this.onMouseUp, true); -} - - -/** - * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM - * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element - * to receive those events - * - * @method setTargetDomElement - * @param domElement {DOMElement} the dom element which will receive mouse and touch events - * @private - */ -PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) -{ - //remove previouse listeners - if( this.interactionDOMElement !== null ) - { - this.interactionDOMElement.style['-ms-content-zooming'] = ''; - this.interactionDOMElement.style['-ms-touch-action'] = ''; - - this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - } - - - if (window.navigator.msPointerEnabled) - { - // time to remove some of that zoom in ja.. - domElement.style['-ms-content-zooming'] = 'none'; - domElement.style['-ms-touch-action'] = 'none'; - - // DO some window specific touch! - } - - this.interactionDOMElement = domElement; - - domElement.addEventListener('mousemove', this.onMouseMove, true); - domElement.addEventListener('mousedown', this.onMouseDown, true); - domElement.addEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - domElement.addEventListener('touchstart', this.onTouchStart, true); - domElement.addEventListener('touchend', this.onTouchEnd, true); - domElement.addEventListener('touchmove', this.onTouchMove, true); -} - - -/** - * updates the state of interactive objects - * - * @method update - * @private - */ -PIXI.InteractionManager.prototype.update = function() -{ - if(!this.target)return; - - // frequency of 30fps?? - var now = Date.now(); - var diff = now - this.last; - diff = (diff * 30) / 1000; - if(diff < 1)return; - this.last = now; - // - - // ok.. so mouse events?? - // yes for now :) - // OPTIMSE - how often to check?? - if(this.dirty) - { - this.dirty = false; - - var len = this.interactiveItems.length; - - for (var i=0; i < len; i++) { - this.interactiveItems[i].interactiveChildren = false; - } - - this.interactiveItems = []; - - if(this.stage.interactive)this.interactiveItems.push(this.stage); - // go through and collect all the objects that are interactive.. - this.collectInteractiveSprite(this.stage, this.stage); - } - - // loop through interactive objects! - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - - //if(!item.visible)continue; - - // OPTIMISATION - only calculate every time if the mousemove function exists.. - // OK so.. does the object have any other interactive functions? - // hit-test the clip! - - - if(item.mouseover || item.mouseout || item.buttonMode) - { - // ok so there are some functions so lets hit test it.. - item.__hit = this.hitTest(item, this.mouse); - this.mouse.target = item; - // ok so deal with interactions.. - // loks like there was a hit! - if(item.__hit) - { - if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; - - if(!item.__isOver) - { - - if(item.mouseover)item.mouseover(this.mouse); - item.__isOver = true; - } - } - else - { - if(item.__isOver) - { - // roll out! - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } - } - - // ---> - } -} - -/** - * Is called when the mouse moves accross the renderer element - * - * @method onMouseMove - * @param event {Event} The DOM event of the mouse moving - * @private - */ -PIXI.InteractionManager.prototype.onMouseMove = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.interactionDOMElement.getBoundingClientRect(); - - this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); - this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); - - var length = this.interactiveItems.length; - var global = this.mouse.global; - - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousemove) - { - //call the function! - item.mousemove(this.mouse); - } - } -} - -/** - * Is called when the mouse button is pressed down on the renderer element - * - * @method onMouseDown - * @param event {Event} The DOM event of a mouse button being pressed down - * @private - */ -PIXI.InteractionManager.prototype.onMouseDown = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - // loop through inteaction tree... - // hit test each item! -> - // get interactive items under point?? - //stage.__i - var length = this.interactiveItems.length; - var global = this.mouse.global; - - var index = 0; - var parent = this.stage; - - // while - // hit test - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousedown || item.click) - { - item.__mouseIsDown = true; - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit) - { - //call the function! - if(item.mousedown)item.mousedown(this.mouse); - item.__isDown = true; - - // just the one! - if(!item.interactiveChildren)break; - } - } - } -} - - -PIXI.InteractionManager.prototype.onMouseOut = function(event) -{ - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.__isOver) - { - this.mouse.target = item; - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } -} - -/** - * Is called when the mouse button is released on the renderer element - * - * @method onMouseUp - * @param event {Event} The DOM event of a mouse button being released - * @private - */ -PIXI.InteractionManager.prototype.onMouseUp = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var global = this.mouse.global; - - - var length = this.interactiveItems.length; - var up = false; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mouseup || item.mouseupoutside || item.click) - { - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit && !up) - { - //call the function! - if(item.mouseup) - { - item.mouseup(this.mouse); - } - if(item.__isDown) - { - if(item.click)item.click(this.mouse); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.mouseupoutside)item.mouseupoutside(this.mouse); - } - } - - item.__isDown = false; - } - } -} - -/** - * Tests if the current mouse coords hit a sprite - * - * @method hitTest - * @param item {DisplayObject} The displayObject to test for a hit - * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit - * @private - */ -PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) -{ - var global = interactionData.global; - - if(item.vcount !== PIXI.visibleCount)return false; - - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, - a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10), - x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; - - interactionData.target = item; - - //a sprite or display object with a hit area defined - if(item.hitArea && item.hitArea.contains) { - if(item.hitArea.contains(x, y)) { - //if(isSprite) - interactionData.target = item; - - return true; - } - - return false; - } - // a sprite with no hitarea defined - else if(isSprite) - { - var width = item.texture.frame.width, - height = item.texture.frame.height, - x1 = -width * item.anchor.x, - y1; - - if(x > x1 && x < x1 + width) - { - y1 = -height * item.anchor.y; - - if(y > y1 && y < y1 + height) - { - // set the target property if a hit is true! - interactionData.target = item - return true; - } - } - } - - var length = item.children.length; - - for (var i = 0; i < length; i++) - { - var tempItem = item.children[i]; - var hit = this.hitTest(tempItem, interactionData); - if(hit) - { - // hmm.. TODO SET CORRECT TARGET? - interactionData.target = item - return true; - } - } - - return false; -} - -/** - * Is called when a touch is moved accross the renderer element - * - * @method onTouchMove - * @param event {Event} The DOM event of a touch moving accross the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchMove = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - touchData.originalEvent = event || window.event; - - // update the touch position - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - } - - var length = this.interactiveItems.length; - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - if(item.touchmove)item.touchmove(touchData); - } -} - -/** - * Is called when a touch is started on the renderer element - * - * @method onTouchStart - * @param event {Event} The DOM event of a touch starting on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchStart = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - - var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - - var touchData = this.pool.pop(); - if(!touchData)touchData = new PIXI.InteractionData(); - - touchData.originalEvent = event || window.event; - - this.touchs[touchEvent.identifier] = touchData; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - - if(item.touchstart || item.tap) - { - item.__hit = this.hitTest(item, touchData); - - if(item.__hit) - { - //call the function! - if(item.touchstart)item.touchstart(touchData); - item.__isDown = true; - item.__touchData = touchData; - - if(!item.interactiveChildren)break; - } - } - } - } -} - -/** - * Is called when a touch is ended on the renderer element - * - * @method onTouchEnd - * @param event {Event} The DOM event of a touch ending on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchEnd = function(event) -{ - //this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - var up = false; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - var itemTouchData = item.__touchData; // <-- Here! - item.__hit = this.hitTest(item, touchData); - - if(itemTouchData == touchData) - { - // so this one WAS down... - touchData.originalEvent = event || window.event; - // hitTest?? - - if(item.touchend || item.tap) - { - if(item.__hit && !up) - { - if(item.touchend)item.touchend(touchData); - if(item.__isDown) - { - if(item.tap)item.tap(touchData); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.touchendoutside)item.touchendoutside(touchData); - } - } - - item.__isDown = false; - } - - item.__touchData = null; - - } - else - { - - } - } - // remove the touch.. - this.pool.push(touchData); - this.touchs[touchEvent.identifier] = null; - } -} - -/** - * Holds all information related to an Interaction event - * - * @class InteractionData - * @constructor - */ -PIXI.InteractionData = function() -{ - /** - * This point stores the global coords of where the touch/mouse event happened - * - * @property global - * @type Point - */ - this.global = new PIXI.Point(); - - // this is here for legacy... but will remove - this.local = new PIXI.Point(); - - /** - * The target Sprite that was interacted with - * - * @property target - * @type Sprite - */ - this.target; - - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @property originalEvent - * @type Event - */ - this.originalEvent; -} - -/** - * This will return the local coords of the specified displayObject for this InteractionData - * - * @method getLocalPosition - * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off - * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject - */ -PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) -{ - var worldTransform = displayObject.worldTransform; - var global = this.global; - - // do a cheeky transform to get the mouse coords; - var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10); - // set the mouse coords... - return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) -} - -// constructor -PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Stage represents the root of the display tree. Everything connected to the stage is rendered - * - * @class Stage - * @extends DisplayObjectContainer - * @constructor - * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format - * like: 0xFFFFFF for white - */ -PIXI.Stage = function(backgroundColor) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create(); - - /** - * Whether or not the stage is interactive - * - * @property interactive - * @type Boolean - */ - this.interactive = true; - - /** - * The interaction manage for this stage, manages all interactive activity on the stage - * - * @property interactive - * @type InteractionManager - */ - this.interactionManager = new PIXI.InteractionManager(this); - - /** - * Whether the stage is dirty and needs to have interactions updated - * - * @property dirty - * @type Boolean - * @private - */ - this.dirty = true; - - this.__childrenAdded = []; - this.__childrenRemoved = []; - - //the stage is it's own stage - this.stage = this; - - //optimize hit detection a bit - this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); - - this.setBackgroundColor(backgroundColor); - this.worldVisible = true; -} - -// constructor -PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Stage.prototype.constructor = PIXI.Stage; - -/** - * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. - * This is useful for when you have other DOM elements ontop of the Canvas element. - * - * @method setInteractionDelegate - * @param domElement {DOMElement} This new domElement which will receive mouse/touch events - */ -PIXI.Stage.prototype.setInteractionDelegate = function(domElement) -{ - this.interactionManager.setTargetDomElement( domElement ); -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Stage.prototype.updateTransform = function() -{ - this.worldAlpha = 1; - this.vcount = PIXI.visibleCount; - - for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - -/** - * A polyfill for Function.prototype.bind - * - * @method bind - */ -if (typeof Function.prototype.bind != 'function') { - Function.prototype.bind = (function () { - var slice = Array.prototype.slice; - return function (thisArg) { - var target = this, boundArgs = slice.call(arguments, 1); - - if (typeof target != 'function') throw new TypeError(); - - function bound() { - var args = boundArgs.concat(slice.call(arguments)); - target.apply(this instanceof bound ? this : thisArg, args); - } - - bound.prototype = (function F(proto) { - proto && (F.prototype = proto); - if (!(this instanceof F)) return new F; - })(target.prototype); - - return bound; - }; - })(); -} - -/** - * A wrapper for ajax requests to be handled cross browser - * - * @class AjaxRequest - * @constructor - */ -var AjaxRequest = PIXI.AjaxRequest = function() -{ - var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE - - if (window.ActiveXObject) - { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) - for (var i=0; i>>>>>>>>") - console.log("_") - var safe = 0; - var tmp = item.first; - console.log(tmp); - - while(tmp._iNext) - { - safe++; - tmp = tmp._iNext; - console.log(tmp); - // console.log(tmp); - - if(safe > 100) - { - console.log("BREAK") - break - } - } -} - - - - - - -/** - * https://github.com/mrdoob/eventtarget.js/ - * THankS mr DOob! - */ - -/** - * Adds event emitter functionality to a class - * - * @class EventTarget - * @example - * function MyEmitter() { - * PIXI.EventTarget.call(this); //mixes in event target stuff - * } - * - * var em = new MyEmitter(); - * em.emit({ type: 'eventName', data: 'some data' }); - */ -PIXI.EventTarget = function () { - - var listeners = {}; - - this.addEventListener = this.on = function ( type, listener ) { - - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - } - - }; - - this.dispatchEvent = this.emit = function ( event ) { - - if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { - - return; - - } - - for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { - - listeners[ event.type ][ i ]( event ); - - } - - }; - - this.removeEventListener = this.off = function ( type, listener ) { - - var index = listeners[ type ].indexOf( listener ); - - if ( index !== - 1 ) { - - listeners[ type ].splice( index, 1 ); - - } - - }; - -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @method autoDetectRenderer - * @static - * @param width {Number} the width of the renderers view - * @param height {Number} the height of the renderers view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) - * - * antialias - */ -PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) -{ - if(!width)width = 800; - if(!height)height = 600; - - // BORROWED from Mr Doob (mrdoob.com) - var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); - - if(webgl) - { - var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); - webgl = !ie; - } - - //console.log(webgl); - if( webgl ) - { - return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); - } - - return new PIXI.CanvasRenderer(width, height, view, transparent); -}; - - - -/* - PolyK library - url: http://polyk.ivank.net - Released under MIT licence. - - Copyright (c) 2012 Ivan Kuckir - - 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. - - This is an amazing lib! - - slightly modified by mat groves (matgroves.com); -*/ - -PIXI.PolyK = {}; - -/** - * Triangulates shapes for webGL graphic fills - * - * @method Triangulate - * @namespace PolyK - * @constructor - */ -PIXI.PolyK.Triangulate = function(p) -{ - var sign = true; - - var n = p.length>>1; - if(n<3) return []; - var tgs = []; - var avl = []; - for(var i=0; i 3) - { - var i0 = avl[(i+0)%al]; - var i1 = avl[(i+1)%al]; - var i2 = avl[(i+2)%al]; - - var ax = p[2*i0], ay = p[2*i0+1]; - var bx = p[2*i1], by = p[2*i1+1]; - var cx = p[2*i2], cy = p[2*i2+1]; - - var earFound = false; - if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) - { - earFound = true; - for(var j=0; j 3*al) - { - // need to flip flip reverse it! - // reset! - if(sign) - { - var tgs = []; - avl = []; - for(var i=0; i= 0) && (v >= 0) && (u + v < 1); -} - -/** - * Checks if a shape is convex - * - * @class _convex - * @namespace PolyK - * @private - */ -PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) -{ - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.initDefaultShaders = function() -{ - PIXI.primitiveShader = new PIXI.PrimitiveShader(); - PIXI.primitiveShader.init(); - - PIXI.stripShader = new PIXI.StripShader(); - PIXI.stripShader.init(); - - PIXI.defaultShader = new PIXI.PixiShader(); - PIXI.defaultShader.init(); - - var gl = PIXI.gl; - var shaderProgram = PIXI.defaultShader.program; - - - gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.activatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.primitiveShader.program); - - gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - - gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); -} - -PIXI.deactivatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - - gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - -} - -PIXI.activateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.stripShader.program); - // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.deactivateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -/* - -SHADER COMPILER HELPERS -*/ - -PIXI.CompileVertexShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); -} - -PIXI.CompileFragmentShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); -} - -PIXI._CompileShader = function(gl, shaderSrc, shaderType) -{ - var src = shaderSrc.join("\n"); - var shader = gl.createShader(shaderType); - gl.shaderSource(shader, src); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - console.log(gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -} - - -PIXI.compileProgram = function(vertexSrc, fragmentSrc) -{ - var gl = PIXI.gl; - var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); - var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); - - var shaderProgram = gl.createProgram(); - - gl.attachShader(shaderProgram, vertexShader); - gl.attachShader(shaderProgram, fragmentShader); - gl.linkProgram(shaderProgram); - - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - console.log("Could not initialise shaders"); - } - - return shaderProgram; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PixiShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision lowp float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", - "}" - ]; - -} - -PIXI.PixiShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - // add those custom shaders! - for (var key in this.uniforms) - { - - // get the uniform locations.. - // program[key] = - this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); - - - } - - this.program = program; -} - -PIXI.PixiShader.prototype.syncUniforms = function() -{ - var gl = PIXI.gl; - - for (var key in this.uniforms) - { - //var - var type = this.uniforms[key].type; - - // need to grow this! - if(type == "f") - { - gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - if(type == "f2") - { - // console.log(this.program[key]) - gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); - } - else if(type == "f4") - { - // console.log(this.uniforms[key].value) - gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if(type == "mat4") - { - gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, false, this.uniforms[key].value); - } - else if(type == "sampler2D") - { - // first texture... - var texture = this.uniforms[key].value; - - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, texture.baseTexture._glTexture); - - gl.uniform1i(this.uniforms[key].uniformLocation, 1); - - // activate texture.. - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - } - } - -} - -PIXI.PixiShader.defaultVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "varying vec2 vTextureCoord;", - - "varying float vColor;", - - "const vec2 center = vec2(-1.0, 1.0);", - "void main(void) {", - "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" -]; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.StripShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform float alpha;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", - "gl_FragColor = gl_FragColor * alpha;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "varying vec2 vTextureCoord;", - "varying vec2 offsetVector;", - "varying float vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" - ]; -} - -PIXI.StripShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PrimitiveShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec4 vColor;", - "void main(void) {", - "gl_FragColor = vColor;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec4 aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "uniform float alpha;", - "varying vec4 vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vColor = aColor * alpha;", - "}" - ]; - -} - -PIXI.PrimitiveShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A set of functions used by the webGL renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.WebGLGraphics = function() -{ - -} - -/** - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param projection {Object} - */ -PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) -{ - var gl = PIXI.gl; - - if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, - buffer:gl.createBuffer(), - indexBuffer:gl.createBuffer()}; - - if(graphics.dirty) - { - graphics.dirty = false; - - if(graphics.clearDirty) - { - graphics.clearDirty = false; - - graphics._webGL.lastIndex = 0; - graphics._webGL.points = []; - graphics._webGL.indices = []; - - } - - PIXI.WebGLGraphics.updateGraphics(graphics); - } - - PIXI.activatePrimitiveShader(); - - // This could be speeded up fo sure! - var m = PIXI.mat3.clone(graphics.worldTransform); - - PIXI.mat3.transpose(m); - - // set the matrix transform for the - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); - - gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); - gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - - gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - - - gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); - - PIXI.deactivatePrimitiveShader(); - - - // return to default shader... -// PIXI.activateShader(PIXI.defaultShader); -} - -/** - * Updates the graphics object - * - * @static - * @private - * @method updateGraphics - * @param graphics {Graphics} - */ -PIXI.WebGLGraphics.updateGraphics = function(graphics) -{ - for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - - if(data.type == PIXI.Graphics.POLY) - { - if(data.fill) - { - if(data.points.length>3) - PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); - } - - if(data.lineWidth > 0) - { - PIXI.WebGLGraphics.buildLine(data, graphics._webGL); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); - } - else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) - { - PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); - } - }; - - graphics._webGL.lastIndex = graphics.graphicsData.length; - - var gl = PIXI.gl; - - graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); - - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); - - graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); -} - -/** - * Builds a rectangle to draw - * - * @static - * @private - * @method buildRectangle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vertPos = verts.length/6; - - // start - verts.push(x, y); - verts.push(r, g, b, alpha); - - verts.push(x + width, y); - verts.push(r, g, b, alpha); - - verts.push(x , y + height); - verts.push(r, g, b, alpha); - - verts.push(x + width, y + height); - verts.push(r, g, b, alpha); - - // insert 2 dead triangles.. - indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) - } - - if(graphicsData.lineWidth) - { - graphicsData.points = [x, y, - x + width, y, - x + width, y + height, - x, y + height, - x, y]; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a circle to draw - * - * @static - * @private - * @method buildCircle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - var totalSegs = 40; - var seg = (Math.PI * 2) / totalSegs ; - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - indices.push(vecPos); - - for (var i=0; i < totalSegs + 1 ; i++) - { - verts.push(x,y, r, g, b, alpha); - - verts.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height, - r, g, b, alpha); - - indices.push(vecPos++, vecPos++); - }; - - indices.push(vecPos-1); - } - - if(graphicsData.lineWidth) - { - graphicsData.points = []; - - for (var i=0; i < totalSegs + 1; i++) - { - graphicsData.points.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height) - }; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a line to draw - * - * @static - * @private - * @method buildLine - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) -{ - // TODO OPTIMISE! - - var wrap = true; - var points = graphicsData.points; - if(points.length == 0)return; - - // if the line width is an odd number add 0.5 to align to a whole pixel - if(graphicsData.lineWidth%2) - { - for (var i = 0; i < points.length; i++) { - points[i] += 0.5; - }; - } - - // get first and last point.. figure out the middle! - var firstPoint = new PIXI.Point( points[0], points[1] ); - var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - // if the first point is the last point - goona have issues :) - if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) - { - points.pop(); - points.pop(); - - lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; - var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - - points.unshift(midPointX, midPointY); - points.push(midPointX, midPointY) - } - - var verts = webGLData.points; - var indices = webGLData.indices; - var length = points.length / 2; - var indexCount = points.length; - var indexStart = verts.length/6; - - // DRAW the Line - var width = graphicsData.lineWidth / 2; - - // sort color - var color = HEXtoRGB(graphicsData.lineColor); - var alpha = graphicsData.lineAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var p1x, p1y, p2x, p2y, p3x, p3y; - var perpx, perpy, perp2x, perp2y, perp3x, perp3y; - var ipx, ipy; - var a1, b1, c1, a2, b2, c2; - var denom, pdist, dist; - - p1x = points[0]; - p1y = points[1]; - - p2x = points[2]; - p2y = points[3]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - // start - verts.push(p1x - perpx , p1y - perpy, - r, g, b, alpha); - - verts.push(p1x + perpx , p1y + perpy, - r, g, b, alpha); - - for (var i = 1; i < length-1; i++) - { - p1x = points[(i-1)*2]; - p1y = points[(i-1)*2 + 1]; - - p2x = points[(i)*2] - p2y = points[(i)*2 + 1] - - p3x = points[(i+1)*2]; - p3y = points[(i+1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - perp2x = -(p2y - p3y); - perp2y = p2x - p3x; - - dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); - perp2x /= dist; - perp2y /= dist; - perp2x *= width; - perp2y *= width; - - a1 = (-perpy + p1y) - (-perpy + p2y); - b1 = (-perpx + p2x) - (-perpx + p1x); - c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); - a2 = (-perp2y + p3y) - (-perp2y + p2y); - b2 = (-perp2x + p2x) - (-perp2x + p3x); - c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - - denom = a1*b2 - a2*b1; - - if(Math.abs(denom) < 0.1 ) - { - - denom+=10.1; - verts.push(p2x - perpx , p2y - perpy, - r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy, - r, g, b, alpha); - - continue; - } - - px = (b1*c2 - b2*c1)/denom; - py = (a2*c1 - a1*c2)/denom; - - - pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - - - if(pdist > 140 * 140) - { - perp3x = perpx - perp2x; - perp3y = perpy - perp2y; - - dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); - perp3x /= dist; - perp3y /= dist; - perp3x *= width; - perp3y *= width; - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x + perp3x, p2y +perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - indexCount++; - } - else - { - - verts.push(px , py); - verts.push(r, g, b, alpha); - - verts.push(p2x - (px-p2x), p2y - (py - p2y)); - verts.push(r, g, b, alpha); - } - } - - p1x = points[(length-2)*2] - p1y = points[(length-2)*2 + 1] - - p2x = points[(length-1)*2] - p2y = points[(length-1)*2 + 1] - - perpx = -(p1y - p2y) - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - verts.push(p2x - perpx , p2y - perpy) - verts.push(r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy) - verts.push(r, g, b, alpha); - - indices.push(indexStart); - - for (var i=0; i < indexCount; i++) - { - indices.push(indexStart++); - }; - - indices.push(indexStart-1); -} - -/** - * Builds a polygon to draw - * - * @static - * @private - * @method buildPoly - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) -{ - var points = graphicsData.points; - if(points.length < 6)return; - - // get first and last point.. figure out the middle! - var verts = webGLData.points; - var indices = webGLData.indices; - - var length = points.length / 2; - - // sort color - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var triangles = PIXI.PolyK.Triangulate(points); - - var vertPos = verts.length / 6; - - for (var i=0; i < triangles.length; i+=3) - { - indices.push(triangles[i] + vertPos); - indices.push(triangles[i] + vertPos); - indices.push(triangles[i+1] + vertPos); - indices.push(triangles[i+2] +vertPos); - indices.push(triangles[i+2] + vertPos); - }; - - for (var i = 0; i < length; i++) - { - verts.push(points[i * 2], points[i * 2 + 1], - r, g, b, alpha); - }; -} - -function HEXtoRGB(hex) { - return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); - -// an instance of the gl context.. -// only one at the moment :/ -PIXI.gl; - -/** - * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer - * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. - * So no need for Sprite Batch's or Sprite Cloud's - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class WebGLRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) - * - */ -PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) -{ - // do a catch.. only 1 webGL renderer.. - - this.transparent = !!transparent; - - this.width = width || 800; - this.height = height || 600; - - this.view = view || document.createElement( 'canvas' ); - this.view.width = this.width; - this.view.height = this.height; - - // deal with losing context.. - var scope = this; - this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) - this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) - - this.batchs = []; - - var options = { - alpha: this.transparent, - antialias:!!antialias, // SPEED UP?? - premultipliedAlpha:false, - stencil:true - } - - //try 'experimental-webgl' - try { - PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); - } catch (e) { - //try 'webgl' - try { - PIXI.gl = this.gl = this.view.getContext("webgl", options); - } catch (e) { - // fail, not able to get a context - throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); - } - } - - PIXI.initDefaultShaders(); - - - - - // PIXI.activateDefaultShader(); - - var gl = this.gl; - - gl.useProgram(PIXI.defaultShader.program); - - - PIXI.WebGLRenderer.gl = gl; - - this.batch = new PIXI.WebGLBatch(gl); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, this.transparent); - - PIXI.projection = new PIXI.Point(400, 300); - PIXI.offset = new PIXI.Point(0, 0); - - // TODO remove thease globals.. - - this.resize(this.width, this.height); - this.contextLost = false; - - //PIXI.pushShader(PIXI.defaultShader); - - this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); - // this.stageRenderGroup. = this.transparent -} - -// constructor -PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; - -/** - * Gets a new WebGLBatch from the pool - * - * @static - * @method getBatch - * @return {WebGLBatch} - * @private - */ -PIXI.WebGLRenderer.getBatch = function() -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * Puts a batch back into the pool - * - * @static - * @method returnBatch - * @param batch {WebGLBatch} The batch to return - * @private - */ -PIXI.WebGLRenderer.returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * Renders the stage to its webGL view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.WebGLRenderer.prototype.render = function(stage) -{ - if(this.contextLost)return; - - - // if rendering a new stage clear the batchs.. - if(this.__stage !== stage) - { - // TODO make this work - // dont think this is needed any more? - this.__stage = stage; - this.stageRenderGroup.setRenderable(stage); - } - - // update any textures - PIXI.WebGLRenderer.updateTextures(); - - // update the scene graph - PIXI.visibleCount++; - stage.updateTransform(); - - var gl = this.gl; - - // -- Does this need to be set every frame? -- // - gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); - gl.clear(gl.COLOR_BUFFER_BIT); - - // HACK TO TEST - - this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - this.stageRenderGroup.render(PIXI.projection); - - // interaction - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // after rendering lets confirm all frames that have been uodated.. - if(PIXI.Texture.frameUpdates.length > 0) - { - for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) - { - PIXI.Texture.frameUpdates[i].updateFrame = false; - }; - - PIXI.Texture.frameUpdates = []; - } -} - -/** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - //TODO break this out into a texture manager... - for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; -} - -/** - * Updates a loaded webgl texture - * - * @static - * @method updateTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.updateTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(!texture._glTexture) - { - texture._glTexture = gl.createTexture(); - } - - if(texture.hasLoaded) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - } -} - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(texture._glTexture) - { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); - } -} - -/** - * resizes the webGL view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the webGL view - * @param height {Number} the new height of the webGL view - */ -PIXI.WebGLRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; - - this.gl.viewport(0, 0, this.width, this.height); - - //var projectionMatrix = this.projectionMatrix; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - //PIXI.size.x = this.width/2; - //PIXI.size.y = -this.height/2; - -// projectionMatrix[0] = 2/this.width; -// projectionMatrix[5] = -2/this.height; -// projectionMatrix[12] = -1; -// projectionMatrix[13] = 1; -} - -/** - * Handles a lost webgl context - * - * @method handleContextLost - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextLost = function(event) -{ - event.preventDefault(); - this.contextLost = true; -} - -/** - * Handles a restored webgl context - * - * @method handleContextRestored - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) -{ - this.gl = this.view.getContext("experimental-webgl", { - alpha: true - }); - - this.initShaders(); - - for(var key in PIXI.TextureCache) - { - var texture = PIXI.TextureCache[key].baseTexture; - texture._glTexture = null; - PIXI.WebGLRenderer.updateTexture(texture); - }; - - for (var i=0; i < this.batchs.length; i++) - { - this.batchs[i].restoreLostContext(this.gl)// - this.batchs[i].dirty = true; - }; - - PIXI._restoreBatchs(this.gl); - - this.contextLost = false; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._batchs = []; - -/** - * @private - */ -PIXI._getBatch = function(gl) -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * @private - */ -PIXI._returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * @private - */ -PIXI._restoreBatchs = function(gl) -{ - for (var i=0; i < PIXI._batchs.length; i++) - { - PIXI._batchs[i].restoreLostContext(gl); - }; -} - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. - * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites - * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled - * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @constructor - * @param gl {WebGLContext} an instance of the webGL context - */ -PIXI.WebGLBatch = function(gl) -{ - this.gl = gl; - - this.size = 0; - - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - this.blendMode = PIXI.blendModes.NORMAL; - this.dynamicSize = 1; -} - -// constructor -PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; - -/** - * Cleans the batch so that is can be returned to an object pool and reused - * - * @method clean - */ -PIXI.WebGLBatch.prototype.clean = function() -{ - this.verticies = []; - this.uvs = []; - this.indices = []; - this.colors = []; - this.dynamicSize = 1; - this.texture = null; - this.last = null; - this.size = 0; - this.head; - this.tail; -} - -/** - * Recreates the buffers in the event of a context loss - * - * @method restoreLostContext - * @param gl {WebGLContext} - */ -PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) -{ - this.gl = gl; - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); -} - -/** - * inits the batch's texture and blend mode based if the supplied sprite - * - * @method init - * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with - * the same base texture and blend mode will be allowed to be added to this batch - */ -PIXI.WebGLBatch.prototype.init = function(sprite) -{ - sprite.batch = this; - this.dirty = true; - this.blendMode = sprite.blendMode; - this.texture = sprite.texture.baseTexture; - this.head = sprite; - this.tail = sprite; - this.size = 1; - - this.growBatch(); -} - -/** - * inserts a sprite before the specified sprite - * - * @method insertBefore - * @param sprite {Sprite} the sprite to be added - * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite - */ -PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - var tempPrev = nextSprite.__prev; - nextSprite.__prev = sprite; - sprite.__next = nextSprite; - - if(tempPrev) - { - sprite.__prev = tempPrev; - tempPrev.__next = sprite; - } - else - { - this.head = sprite; - } -} - -/** - * inserts a sprite after the specified sprite - * - * @method insertAfter - * @param sprite {Sprite} the sprite to be added - * @param previousSprite {Sprite} the first sprite will be inserted after this sprite - */ -PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - - var tempNext = previousSprite.__next; - previousSprite.__next = sprite; - sprite.__prev = previousSprite; - - if(tempNext) - { - sprite.__next = tempNext; - tempNext.__prev = sprite; - } - else - { - this.tail = sprite - } -} - -/** - * removes a sprite from the batch - * - * @method remove - * @param sprite {Sprite} the sprite to be removed - */ -PIXI.WebGLBatch.prototype.remove = function(sprite) -{ - this.size--; - - if(this.size == 0) - { - sprite.batch = null; - sprite.__prev = null; - sprite.__next = null; - return; - } - - if(sprite.__prev) - { - sprite.__prev.__next = sprite.__next; - } - else - { - this.head = sprite.__next; - this.head.__prev = null; - } - - if(sprite.__next) - { - sprite.__next.__prev = sprite.__prev; - } - else - { - this.tail = sprite.__prev; - this.tail.__next = null - } - - sprite.batch = null; - sprite.__next = null; - sprite.__prev = null; - this.dirty = true; -} - -/** - * Splits the batch into two with the specified sprite being the start of the new batch. - * - * @method split - * @param sprite {Sprite} the sprite that indicates where the batch should be split - * @return {WebGLBatch} the new batch - */ -PIXI.WebGLBatch.prototype.split = function(sprite) -{ - this.dirty = true; - - var batch = new PIXI.WebGLBatch(this.gl); - batch.init(sprite); - batch.texture = this.texture; - batch.tail = this.tail; - - this.tail = sprite.__prev; - this.tail.__next = null; - - sprite.__prev = null; - // return a splite batch! - - // TODO this size is wrong! - // need to recalculate :/ problem with a linked list! - // unless it gets calculated in the "clean"? - - // need to loop through items as there is no way to know the length on a linked list :/ - var tempSize = 0; - while(sprite) - { - tempSize++; - sprite.batch = batch; - sprite = sprite.__next; - } - - batch.size = tempSize; - this.size -= tempSize; - - return batch; -} - -/** - * Merges two batchs together - * - * @method merge - * @param batch {WebGLBatch} the batch that will be merged - */ -PIXI.WebGLBatch.prototype.merge = function(batch) -{ - this.dirty = true; - - this.tail.__next = batch.head; - batch.head.__prev = this.tail; - - this.size += batch.size; - - this.tail = batch.tail; - - var sprite = batch.head; - while(sprite) - { - sprite.batch = this; - sprite = sprite.__next; - } -} - -/** - * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this - * function is used to increase the size of the batch. It also creates a little extra room so - * that the batch does not need to be resized every time a sprite is added - * - * @method growBatch - */ -PIXI.WebGLBatch.prototype.growBatch = function() -{ - var gl = this.gl; - if( this.size == 1) - { - this.dynamicSize = 1; - } - else - { - this.dynamicSize = this.size * 1.5 - } - // grow verts - this.verticies = new Float32Array(this.dynamicSize * 8); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - - this.uvs = new Float32Array( this.dynamicSize * 8 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); - - this.dirtyUVS = true; - - this.colors = new Float32Array( this.dynamicSize * 4 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); - - this.dirtyColors = true; - - this.indices = new Uint16Array(this.dynamicSize * 6); - var length = this.indices.length/6; - - for (var i=0; i < length; i++) - { - var index2 = i * 6; - var index3 = i * 4; - this.indices[index2 + 0] = index3 + 0; - this.indices[index2 + 1] = index3 + 1; - this.indices[index2 + 2] = index3 + 2; - this.indices[index2 + 3] = index3 + 0; - this.indices[index2 + 4] = index3 + 2; - this.indices[index2 + 5] = index3 + 3; - }; - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); -} - -/** - * Refresh's all the data in the batch and sync's it with the webGL buffers - * - * @method refresh - */ -PIXI.WebGLBatch.prototype.refresh = function() -{ - var gl = this.gl; - - if (this.dynamicSize < this.size) - { - this.growBatch(); - } - - var indexRun = 0; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; - var a, b, c, d, tx, ty; - - var displayObject = this.head; - - while(displayObject) - { - index = indexRun * 8; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - this.uvs[index + 0] = frame.x / tw; - this.uvs[index +1] = frame.y / th; - - this.uvs[index +2] = (frame.x + frame.width) / tw; - this.uvs[index +3] = frame.y / th; - - this.uvs[index +4] = (frame.x + frame.width) / tw; - this.uvs[index +5] = (frame.y + frame.height) / th; - - this.uvs[index +6] = frame.x / tw; - this.uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - - colorIndex = indexRun * 4; - this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; - - displayObject = displayObject.__next; - - indexRun ++; - } - - this.dirtyUVS = true; - this.dirtyColors = true; -} - -/** - * Updates all the relevant geometry and uploads the data to the GPU - * - * @method update - */ -PIXI.WebGLBatch.prototype.update = function() -{ - var gl = this.gl; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 - - var a, b, c, d, tx, ty; - - var indexRun = 0; - - var displayObject = this.head; - var verticies = this.verticies; - var uvs = this.uvs; - var colors = this.colors; - - while(displayObject) - { - if(displayObject.vcount === PIXI.visibleCount) - { - width = displayObject.texture.frame.width; - height = displayObject.texture.frame.height; - - // TODO trim?? - aX = displayObject.anchor.x;// - displayObject.texture.trim.x - aY = displayObject.anchor.y; //- displayObject.texture.trim.y - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - index = indexRun * 8; - - worldTransform = displayObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - verticies[index + 0 ] = a * w1 + c * h1 + tx; - verticies[index + 1 ] = d * h1 + b * w1 + ty; - - verticies[index + 2 ] = a * w0 + c * h1 + tx; - verticies[index + 3 ] = d * h1 + b * w0 + ty; - - verticies[index + 4 ] = a * w0 + c * h0 + tx; - verticies[index + 5 ] = d * h0 + b * w0 + ty; - - verticies[index + 6] = a * w1 + c * h0 + tx; - verticies[index + 7] = d * h0 + b * w1 + ty; - - if(displayObject.updateFrame || displayObject.texture.updateFrame) - { - this.dirtyUVS = true; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - uvs[index + 0] = frame.x / tw; - uvs[index +1] = frame.y / th; - - uvs[index +2] = (frame.x + frame.width) / tw; - uvs[index +3] = frame.y / th; - - uvs[index +4] = (frame.x + frame.width) / tw; - uvs[index +5] = (frame.y + frame.height) / th; - - uvs[index +6] = frame.x / tw; - uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - } - - // TODO this probably could do with some optimisation.... - if(displayObject.cacheAlpha != displayObject.worldAlpha) - { - displayObject.cacheAlpha = displayObject.worldAlpha; - - var colorIndex = indexRun * 4; - colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; - this.dirtyColors = true; - } - } - else - { - index = indexRun * 8; - - verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; - } - - indexRun++; - displayObject = displayObject.__next; - } -} - -/** - * Draws the batch to the frame buffer - * - * @method render - */ -PIXI.WebGLBatch.prototype.render = function(start, end) -{ - start = start || 0; - - if(end == undefined)end = this.size; - - if(this.dirty) - { - this.refresh(); - this.dirty = false; - } - - if (this.size == 0)return; - - this.update(); - var gl = this.gl; - - //TODO optimize this! - - var shaderProgram = PIXI.defaultShader; - - //gl.useProgram(shaderProgram); - - // update the verts.. - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - // ok.. - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) - gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - // update the uvs - //var isDefault = (shaderProgram == PIXI.shaderProgram) - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - if(this.dirtyUVS) - { - this.dirtyUVS = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); - } - - gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); - - // update color! - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - - if(this.dirtyColors) - { - this.dirtyColors = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); - } - - gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - var len = end - start; - - // DRAW THAT this! - gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be - * grouped into a batch. All the sprites in a batch can then be drawn in one go by the - * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch - * even if the batch only contains one sprite. Batching is handled automatically by the - * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @contructor - * @param gl {WebGLContext} An instance of the webGL context - */ -PIXI.WebGLRenderGroup = function(gl, transparent) -{ - this.gl = gl; - this.root; - - this.backgroundColor; - this.transparent = transparent == undefined ? true : transparent; - - this.batchs = []; - this.toRemove = []; - console.log(this.transparent) - this.filterManager = new PIXI.WebGLFilterManager(this.transparent); -} - -// constructor -PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; - -/** - * Add a display object to the webgl renderer - * - * @method setRenderable - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) -{ - // has this changed?? - if(this.root)this.removeDisplayObjectAndChildren(this.root); - - displayObject.worldVisible = displayObject.visible; - - // soooooo // - // to check if any batchs exist already?? - - // TODO what if its already has an object? should remove it - this.root = displayObject; - this.addDisplayObjectAndChildren(displayObject); -} - -/** - * Renders the stage to its webgl view - * - * @method render - * @param projection {Object} - */ -PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - - var gl = this.gl; - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - // will render all the elements in the group - var renderable; - - for (var i=0; i < this.batchs.length; i++) - { - - renderable = this.batchs[i]; - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - continue; - } - - // render special - this.renderSpecial(renderable, projection); - } - -} - -/** - * Renders a specific displayObject - * - * @method renderSpecific - * @param displayObject {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - var gl = this.gl; - - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - // to do! - // render part of the scene... - - var startIndex; - var startBatchIndex; - - var endIndex; - var endBatchIndex; - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.first; - while(nextRenderable._iNext) - { - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - nextRenderable = nextRenderable._iNext; - } - var startBatch = nextRenderable.batch; - //console.log(nextRenderable); - - //console.log(renderable) - if(nextRenderable instanceof PIXI.Sprite) - { - startBatch = nextRenderable.batch; - - var head = startBatch.head; - var next = head; - - // ok now we have the batch.. need to find the start index! - if(head == nextRenderable) - { - startIndex = 0; - } - else - { - startIndex = 1; - - while(head.__next != nextRenderable) - { - startIndex++; - head = head.__next; - } - } - } - else - { - startBatch = nextRenderable; - } - - // Get the LAST renderable object - var lastRenderable = displayObject.last; - while(lastRenderable._iPrev) - { - if(lastRenderable.renderable && lastRenderable.__renderGroup)break; - lastRenderable = lastRenderable._iNext; - } - - if(lastRenderable instanceof PIXI.Sprite) - { - endBatch = lastRenderable.batch; - - var head = endBatch.head; - - if(head == lastRenderable) - { - endIndex = 0; - } - else - { - endIndex = 1; - - while(head.__next != lastRenderable) - { - endIndex++; - head = head.__next; - } - } - } - else - { - endBatch = lastRenderable; - } - - //console.log(endBatch); - // TODO - need to fold this up a bit! - - if(startBatch == endBatch) - { - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex, endIndex+1); - } - else - { - this.renderSpecial(startBatch, projection); - } - return; - } - - // now we have first and last! - startBatchIndex = this.batchs.indexOf(startBatch); - endBatchIndex = this.batchs.indexOf(endBatch); - - // DO the first batch - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex); - } - else - { - this.renderSpecial(startBatch, projection); - } - - // DO the middle batchs.. - for (var i=startBatchIndex+1; i < endBatchIndex; i++) - { - renderable = this.batchs[i]; - - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - } - else - { - this.renderSpecial(renderable, projection); - } - } - - // DO the last batch.. - if(endBatch instanceof PIXI.WebGLBatch) - { - endBatch.render(0, endIndex+1); - } - else - { - this.renderSpecial(endBatch, projection); - } -} - -/** - * Renders a specific renderable - * - * @method renderSpecial - * @param renderable {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) -{ - - var worldVisible = renderable.vcount === PIXI.visibleCount - - - if(renderable instanceof PIXI.TilingSprite) - { - if(worldVisible)this.renderTilingSprite(renderable, projection); - } - else if(renderable instanceof PIXI.Strip) - { - if(worldVisible)this.renderStrip(renderable, projection); - } - else if(renderable instanceof PIXI.CustomRenderable) - { - if(worldVisible) renderable.renderWebGL(this, projection); - } - else if(renderable instanceof PIXI.Graphics) - { - if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); - } - else if(renderable instanceof PIXI.FilterBlock) - { - this.handleFilterBlock(renderable, projection); - } -} - -flip = false; -var maskStack = []; -var maskPosition = 0; - -//var usedMaskStack = []; - -PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) -{ - /* - * for now only masks are supported.. - */ - var gl = PIXI.gl; - - if(filterBlock.open) - { - if(filterBlock.data instanceof Array) - { - this.filterManager.pushFilter(filterBlock); - // ok so.. - - } - else - { - maskPosition++; - - maskStack.push(filterBlock) - - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - - PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - } - else - { - if(filterBlock.data instanceof Array) - { - this.filterManager.popFilter(); - } - else - { - var maskData = maskStack.pop(filterBlock) - - - if(maskData) - { - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - - PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - }; - - gl.disable(gl.STENCIL_TEST); - } - } -} - -/** - * Updates a webgl texture - * - * @method updateTexture - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) -{ - - // TODO definitely can optimse this function.. - - this.removeObject(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = displayObject.first; - while(previousRenderable != this.root) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - this.insertObject(displayObject, previousRenderable, nextRenderable); -} - -/** - * Adds filter blocks - * - * @method addFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) -{ - start.__renderGroup = this; - end.__renderGroup = this; - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = start; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - this.insertAfter(start, previousRenderable); - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var previousRenderable2 = end; - while(previousRenderable2 != this.root.first) - { - previousRenderable2 = previousRenderable2._iPrev; - if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; - } - this.insertAfter(end, previousRenderable2); -} - -/** - * Remove filter blocks - * - * @method removeFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) -{ - this.removeObject(start); - this.removeObject(end); -} - -/** - * Adds a display object and children to the webgl context - * - * @method addDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - - var previousRenderable = displayObject.first; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - // one the display object hits this. we can break the loop - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - do - { - tempObject.__renderGroup = this; - - if(tempObject.renderable) - { - - this.insertObject(tempObject, previousRenderable, nextRenderable); - previousRenderable = tempObject; - } - - tempObject = tempObject._iNext; - } - while(tempObject != testObject) -} - -/** - * Removes a display object and children to the webgl context - * - * @method removeDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup != this)return; - -// var displayObject = displayObject.first; - var lastObject = displayObject.last; - do - { - displayObject.__renderGroup = null; - if(displayObject.renderable)this.removeObject(displayObject); - displayObject = displayObject._iNext; - } - while(displayObject) -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertObject - * @param displayObject {DisplayObject} - * @param previousObject {DisplayObject} - * @param nextObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) -{ - // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED - var previousSprite = previousObject; - var nextSprite = nextObject; - - /* - * so now we have the next renderable and the previous renderable - * - */ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch - var nextBatch - - if(previousSprite instanceof PIXI.Sprite) - { - previousBatch = previousSprite.batch; - if(previousBatch) - { - if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) - { - previousBatch.insertAfter(displayObject, previousSprite); - return; - } - } - } - else - { - // TODO reword! - previousBatch = previousSprite; - } - - if(nextSprite) - { - if(nextSprite instanceof PIXI.Sprite) - { - nextBatch = nextSprite.batch; - - //batch may not exist if item was added to the display list but not to the webGL - if(nextBatch) - { - if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) - { - nextBatch.insertBefore(displayObject, nextSprite); - return; - } - else - { - if(nextBatch == previousBatch) - { - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(nextSprite); - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var batch = PIXI.WebGLRenderer.getBatch(); - - var index = this.batchs.indexOf( previousBatch ); - batch.init(displayObject); - this.batchs.splice(index+1, 0, batch, splitBatch); - - return; - } - } - } - } - else - { - // TODO re-word! - - nextBatch = nextSprite; - } - } - - /* - * looks like it does not belong to any batch! - * but is also not intersecting one.. - * time to create anew one! - */ - - var batch = PIXI.WebGLRenderer.getBatch(); - batch.init(displayObject); - - if(previousBatch) // if this is invalid it means - { - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, batch); - } - else - { - this.batchs.push(batch); - } - - return; - } - else if(displayObject instanceof PIXI.TilingSprite) - { - - // add to a batch!! - this.initTilingSprite(displayObject); - // this.batchs.push(displayObject); - - } - else if(displayObject instanceof PIXI.Strip) - { - // add to a batch!! - this.initStrip(displayObject); - // this.batchs.push(displayObject); - } - else if(displayObject)// instanceof PIXI.Graphics) - { - //displayObject.initWebGL(this); - - // add to a batch!! - //this.initStrip(displayObject); - //this.batchs.push(displayObject); - } - - this.insertAfter(displayObject, previousSprite); - - // insert and SPLIT! - -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertAfter - * @param item {DisplayObject} - * @param displayObject {DisplayObject} The object to insert - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) -{ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch = displayObject.batch; - - if(previousBatch) - { - // so this object is in a batch! - - // is it not? need to split the batch - if(previousBatch.tail == displayObject) - { - // is it tail? insert in to batchs - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item); - } - else - { - // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // - - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(displayObject.__next); - - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item, splitBatch); - } - } - else - { - this.batchs.push(item); - } - } - else - { - var index = this.batchs.indexOf( displayObject ); - this.batchs.splice(index+1, 0, item); - } -} - -/** - * Removes a displayObject from the linked list - * - * @method removeObject - * @param displayObject {DisplayObject} The object to remove - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) -{ - // loop through children.. - // display object // - - // add a child from the render group.. - // remove it and all its children! - //displayObject.cacheVisible = false;//displayObject.visible; - - /* - * removing is a lot quicker.. - * - */ - var batchToRemove; - - if(displayObject instanceof PIXI.Sprite) - { - // should always have a batch! - var batch = displayObject.batch; - if(!batch)return; // this means the display list has been altered befre rendering - - batch.remove(displayObject); - - if(batch.size==0) - { - batchToRemove = batch; - } - } - else - { - batchToRemove = displayObject; - } - - /* - * Looks like there is somthing that needs removing! - */ - if(batchToRemove) - { - var index = this.batchs.indexOf( batchToRemove ); - if(index == -1)return;// this means it was added then removed before rendered - - // ok so.. check to see if you adjacent batchs should be joined. - // TODO may optimise? - if(index == 0 || index == this.batchs.length-1) - { - // wha - eva! just get of the empty batch! - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - - return; - } - - if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) - { - if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) - { - //console.log("MERGE") - this.batchs[index-1].merge(this.batchs[index+1]); - - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); - this.batchs.splice(index, 2); - return; - } - } - - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - } -} - - -/** - * Initializes a tiling sprite - * - * @method initTilingSprite - * @param sprite {TilingSprite} The tiling sprite to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) -{ - var gl = this.gl; - - // make the texture tilable.. - - sprite.verticies = new Float32Array([0, 0, - sprite.width, 0, - sprite.width, sprite.height, - 0, sprite.height]); - - sprite.uvs = new Float32Array([0, 0, - 1, 0, - 1, 1, - 0, 1]); - - sprite.colors = new Float32Array([1,1,1,1]); - - sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); - - sprite._vertexBuffer = gl.createBuffer(); - sprite._indexBuffer = gl.createBuffer(); - sprite._uvBuffer = gl.createBuffer(); - sprite._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); - -// return ( (x > 0) && ((x & (x - 1)) == 0) ); - - if(sprite.texture.baseTexture._glTexture) - { - gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - sprite.texture.baseTexture._powerOf2 = true; - } - else - { - sprite.texture.baseTexture._powerOf2 = true; - } -} - -/** - * Renders a Strip - * - * @method renderStrip - * @param strip {Strip} The strip to render - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) -{ - var gl = this.gl; - - PIXI.activateStripShader(); - - var shader = PIXI.stripShader; - - var program = shader.program; - - var m = PIXI.mat3.clone(strip.worldTransform); - - PIXI.mat3.transpose(m); - -// console.log(projection) - // set the matrix transform for the - gl.uniformMatrix3fv(shader.translationMatrix, false, m); - gl.uniform2f(shader.projectionVector, projection.x, projection.y); - gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(shader.alpha, strip.worldAlpha); - - /* - if(strip.blendMode == PIXI.blendModes.NORMAL) - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - } - else - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); - } - */ - - //console.log("!!") - if(!strip.dirty) - { - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - } - else - { - strip.dirty = false; - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - // console.log(strip.texture.baseTexture._glTexture) - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); - - } - - gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - - PIXI.deactivateStripShader(); - //gl.useProgram(PIXI.currentProgram); -} - -/** - * Renders a TilingSprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tiling sprite to render - * @param projectionMatrix {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) -{ - var gl = this.gl; - - - var shaderProgram = PIXI.shaderProgram; - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - var offsetX = tilePosition.x/sprite.texture.baseTexture.width; - var offsetY = tilePosition.y/sprite.texture.baseTexture.height; - - var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; - var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; - - sprite.uvs[0] = 0 - offsetX; - sprite.uvs[1] = 0 - offsetY; - - sprite.uvs[2] = (1 * scaleX) -offsetX; - sprite.uvs[3] = 0 - offsetY; - - sprite.uvs[4] = (1 *scaleX) - offsetX; - sprite.uvs[5] = (1 *scaleY) - offsetY; - - sprite.uvs[6] = 0 - offsetX; - sprite.uvs[7] = (1 *scaleY) - offsetY; - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) - - this.renderStrip(sprite, projectionMatrix); -} - -/** - * Initializes a strip to be rendered - * - * @method initStrip - * @param strip {Strip} The strip to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) -{ - // build the strip! - var gl = this.gl; - var shaderProgram = this.shaderProgram; - - strip._vertexBuffer = gl.createBuffer(); - strip._indexBuffer = gl.createBuffer(); - strip._uvBuffer = gl.createBuffer(); - strip._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); - - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.WebGLFilterManager = function(transparent) -{ - this.transparent = transparent; - - this.filterStack = []; - this.texturePool = []; - - this.offsetX = 0; - this.offsetY = 0; - - this.initShaderBuffers(); -} - -// API - -PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) -{ - this.width = projection.x * 2; - this.height = -projection.y * 2; - this.buffer = buffer; -} - -PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) -{ - var gl = PIXI.gl; - - // filter program - // OPTIMISATION - the first filter is free if its a simple color change? - this.filterStack.push(filterBlock); - - var filter = filterBlock.filterPasses[0]; - - - - this.offsetX += filterBlock.target.filterArea.x; - this.offsetY += filterBlock.target.filterArea.y; - - - - - - var texture = this.texturePool.pop(); - if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); - - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - this.getBounds(filterBlock.target); - - // addpadding? - //displayObject.filterArea.x - - var filterArea = filterBlock.target.filterArea; - - var padidng = filter.padding; - filterArea.x -= padidng; - filterArea.y -= padidng; - filterArea.width += padidng * 2; - filterArea.height += padidng * 2; - - // cap filter to screen size.. - if(filterArea.x < 0)filterArea.x = 0; - if(filterArea.width > this.width)filterArea.width = this.width; - if(filterArea.y < 0)filterArea.y = 0; - if(filterArea.height > this.height)filterArea.height = this.height; - - - //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); - - // console.log(filterArea) - // set view port - gl.viewport(0, 0, filterArea.width, filterArea.height); - - PIXI.projection.x = filterArea.width/2; - PIXI.projection.y = -filterArea.height/2; - - PIXI.offset.x = -filterArea.x; - PIXI.offset.y = -filterArea.y; - - //console.log(PIXI.defaultShader.projectionVector) - // update projection - gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); - //PIXI.primitiveProgram - - gl.colorMask(true, true, true, true); - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - //filter.texture = texture; - filterBlock._glFilterTexture = texture; - - //console.log("PUSH") -} - - -PIXI.WebGLFilterManager.prototype.popFilter = function() -{ - - var gl = PIXI.gl; - - var filterBlock = this.filterStack.pop(); - - - - var filterArea = filterBlock.target.filterArea; - - var texture = filterBlock._glFilterTexture; - - if(filterBlock.filterPasses.length > 1) - { - gl.viewport(0, 0, filterArea.width, filterArea.height); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = 0; - this.vertexArray[1] = filterArea.height; - - this.vertexArray[2] = filterArea.width; - this.vertexArray[3] = filterArea.height; - - this.vertexArray[4] = 0; - this.vertexArray[5] = 0; - - this.vertexArray[6] = filterArea.width; - this.vertexArray[7] = 0; - - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - // nnow set the uvs.. - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - var inputTexture = texture; - var outputTexture = this.texturePool.pop(); - if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); - - // need to clear this FBO as it may have some left over elements from a prvious filter. - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.disable(gl.BLEND); - - for (var i = 0; i < filterBlock.filterPasses.length-1; i++) - { - var filterPass = filterBlock.filterPasses[i]; - - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); - - // draw texture.. - //filterPass.applyFilterPass(filterArea.width, filterArea.height); - this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); - - // swap the textures.. - var temp = inputTexture; - inputTexture = outputTexture; - outputTexture = temp; - - }; - - gl.enable(gl.BLEND); - - texture = inputTexture; - this.texturePool.push(outputTexture); - } - - var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; - - this.offsetX -= filterArea.x; - this.offsetY -= filterArea.y; - - - var sizeX = this.width; - var sizeY = this.height; - - var offsetX = 0; - var offsetY = 0; - - var buffer = this.buffer; - - // time to render the filters texture to the previous scene - if(this.filterStack.length === 0) - { - gl.colorMask(true, true, true, this.transparent); - } - else - { - var currentFilter = this.filterStack[this.filterStack.length-1]; - var filterArea = currentFilter.target.filterArea; - - sizeX = filterArea.width; - sizeY = filterArea.height; - - offsetX = filterArea.x; - offsetY = filterArea.y; - - buffer = currentFilter._glFilterTexture.frameBuffer; - } - - - - // TODO need toremove thease global elements.. - PIXI.projection.x = sizeX/2; - PIXI.projection.y = -sizeY/2; - - PIXI.offset.x = offsetX; - PIXI.offset.y = offsetY; - - - var filterArea = filterBlock.target.filterArea; - var x = filterArea.x-offsetX; - var y = filterArea.y-offsetY; - - // update the buffers.. - // make sure to flip the y! - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = x; - this.vertexArray[1] = y + filterArea.height; - - this.vertexArray[2] = x + filterArea.width; - this.vertexArray[3] = y + filterArea.height; - - this.vertexArray[4] = x; - this.vertexArray[5] = y; - - this.vertexArray[6] = x + filterArea.width; - this.vertexArray[7] = y; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - gl.viewport(0, 0, sizeX, sizeY); - // bind the buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - // apply! - //filter.applyFilterPass(sizeX, sizeY); - this.applyFilterPass(filter, filterArea, sizeX, sizeY); - - // now restore the regular shader.. - gl.useProgram(PIXI.defaultShader.program); - gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); - - // return the texture to the pool - this.texturePool.push(texture); - filterBlock._glFilterTexture = null; -} - -PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) -{ - // use program - var gl = PIXI.gl; - - if(!filter.shader) - { - var shader = new PIXI.PixiShader(); - - shader.fragmentSrc = filter.fragmentSrc; - shader.uniforms = filter.uniforms; - shader.init(); - - filter.shader = shader; - } - - var shader = filter.shader; - - // set the shader - gl.useProgram(shader.program); - - gl.uniform2f(shader.projectionVector, width/2, -height/2); - gl.uniform2f(shader.offsetVector, 0,0) - - if(filter.uniforms.dimensions) - { - //console.log(filter.uniforms.dimensions) - filter.uniforms.dimensions.value[0] = this.width;//width; - filter.uniforms.dimensions.value[1] = this.height;//height; - filter.uniforms.dimensions.value[2] = this.vertexArray[0]; - filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; - // console.log(this.vertexArray[5]) - } - - shader.syncUniforms(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // draw the filter... - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); -} - -PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() -{ - var gl = PIXI.gl; - - // create some buffers - this.vertexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // bind and upload the vertexs.. - // keep a refferance to the vertexFloatData.. - this.vertexArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.vertexArray, - gl.STATIC_DRAW); - - - // bind and upload the uv buffer - this.uvArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.uvArray, - gl.STATIC_DRAW); - - // bind and upload the index - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData( - gl.ELEMENT_ARRAY_BUFFER, - new Uint16Array([0, 1, 2, 1, 3, 2]), - gl.STATIC_DRAW); -} - -PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) -{ - // time to get the width and height of the object! - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; - var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - - var maxX = -Infinity; - var maxY = -Infinity; - - var minX = Infinity; - var minY = Infinity; - - do - { - // TODO can be optimized! - what if there is no scale / rotation? - - if(tempObject.visible) - { - if(tempObject instanceof PIXI.Sprite) - { - width = tempObject.texture.frame.width; - height = tempObject.texture.frame.height; - - // TODO trim?? - aX = tempObject.anchor.x; - aY = tempObject.anchor.y; - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - doTest = true; - } - else if(tempObject instanceof PIXI.Graphics) - { - tempObject.updateFilterBounds(); - - var bounds = tempObject.bounds; - - width = bounds.width; - height = bounds.height; - - w0 = bounds.x - w1 = bounds.x + bounds.width; - - h0 = bounds.y - h1 = bounds.y + bounds.height; - - doTest = true; - } - } - - if(doTest) - { - worldTransform = tempObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - x1 = a * w1 + c * h1 + tx; - y1 = d * h1 + b * w1 + ty; - - x2 = a * w0 + c * h1 + tx; - y2 = d * h1 + b * w0 + ty; - - x3 = a * w0 + c * h0 + tx; - y3 = d * h0 + b * w0 + ty; - - x4 = a * w1 + c * h0 + tx; - y4 = d * h0 + b * w1 + ty; - - minX = x1 < minX ? x1 : minX; - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y1 < minY ? y1 : minY; - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x1 > maxX ? x1 : maxX; - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1 > maxY ? y1 : maxY; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - } - - doTest = false; - tempObject = tempObject._iNext; - - } - while(tempObject != testObject) - - // maximum bounds is the size of the screen.. - //minX = minX > 0 ? minX : 0; - //minY = minY > 0 ? minY : 0; - - displayObject.filterArea.x = minX; - displayObject.filterArea.y = minY; - -// console.log(maxX+ " : " + minX) - displayObject.filterArea.width = maxX - minX; - displayObject.filterArea.height = maxY - minY; -} - -PIXI.FilterTexture = function(width, height) -{ - var gl = PIXI.gl; - - // next time to create a frame buffer and texture - this.frameBuffer = gl.createFramebuffer(); - this.texture = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - this.resize(width, height); -} - -PIXI.FilterTexture.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - var gl = PIXI.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class CanvasRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - */ -PIXI.CanvasRenderer = function(width, height, view, transparent) -{ - this.transparent = transparent; - - /** - * The width of the canvas view - * - * @property width - * @type Number - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @property height - * @type Number - * @default 600 - */ - this.height = height || 600; - - /** - * The canvas element that the everything is drawn to - * - * @property view - * @type Canvas - */ - this.view = view || document.createElement( 'canvas' ); - - /** - * The canvas context that the everything is drawn to - * @property context - * @type Canvas 2d Context - */ - this.context = this.view.getContext("2d"); - - this.refresh = true; - // hack to enable some hardware acceleration! - //this.view.style["transform"] = "translatez(0)"; - - this.view.width = this.width; - this.view.height = this.height; - this.count = 0; -} - -// constructor -PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; - -/** - * Renders the stage to its canvas view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.CanvasRenderer.prototype.render = function(stage) -{ - - //stage.__childrenAdded = []; - //stage.__childrenRemoved = []; - - // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - - PIXI.visibleCount++; - stage.updateTransform(); - - // update the background color - if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; - - this.context.setTransform(1,0,0,1,0,0); - this.context.clearRect(0, 0, this.width, this.height) - this.renderDisplayObject(stage); - //as - - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // remove frame updates.. - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates = []; - } - - -} - -/** - * resizes the canvas view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the canvas view - * @param height {Number} the new height of the canvas view - */ -PIXI.CanvasRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; -} - -/** - * Renders a display object - * - * @method renderDisplayObject - * @param displayObject {DisplayObject} The displayObject to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) -{ - // no loger recurrsive! - var transform; - var context = this.context; - - context.globalCompositeOperation = 'source-over'; - - // one the display object hits this. we can break the loop - var testObject = displayObject.last._iNext; - displayObject = displayObject.first; - - do - { - transform = displayObject.worldTransform; - - if(!displayObject.visible) - { - displayObject = displayObject.last._iNext; - continue; - } - - if(!displayObject.renderable) - { - displayObject = displayObject._iNext; - continue; - } - - if(displayObject instanceof PIXI.Sprite) - { - - var frame = displayObject.texture.frame; - - if(frame && frame.width && frame.height) - { - context.globalAlpha = displayObject.worldAlpha; - - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - - context.drawImage(displayObject.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - (displayObject.anchor.x) * -frame.width, - (displayObject.anchor.y) * -frame.height, - frame.width, - frame.height); - } - } - else if(displayObject instanceof PIXI.Strip) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderStrip(displayObject); - } - else if(displayObject instanceof PIXI.TilingSprite) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderTilingSprite(displayObject); - } - else if(displayObject instanceof PIXI.CustomRenderable) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - displayObject.renderCanvas(this); - } - else if(displayObject instanceof PIXI.Graphics) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - PIXI.CanvasGraphics.renderGraphics(displayObject, context); - } - else if(displayObject instanceof PIXI.FilterBlock) - { - if(displayObject.data instanceof PIXI.Graphics) - { - var mask = displayObject.data; - - if(displayObject.open) - { - context.save(); - - var cacheAlpha = mask.alpha; - var maskTransform = mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(mask, context); - context.clip(); - - mask.worldAlpha = cacheAlpha; - } - else - { - context.restore(); - } - } - else - { - // only masks supported right now! - } - } - // count++ - displayObject = displayObject._iNext; - - - } - while(displayObject != testObject) - - -} - -/** - * Renders a flat strip - * - * @method renderStripFlat - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) -{ - var context = this.context; - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - - context.beginPath(); - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - }; - - context.fillStyle = "#FF0000"; - context.fill(); - context.closePath(); -} - -/** - * Renders a tiling sprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tilingsprite to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) -{ - var context = this.context; - - context.globalAlpha = sprite.worldAlpha; - - if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); - - context.beginPath(); - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - // offset - context.scale(tileScale.x,tileScale.y); - context.translate(tilePosition.x, tilePosition.y); - - context.fillStyle = sprite.__tilePattern; - context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); - - context.scale(1/tileScale.x, 1/tileScale.y); - context.translate(-tilePosition.x, -tilePosition.y); - - context.closePath(); -} - -/** - * Renders a strip - * - * @method renderStrip - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStrip = function(strip) -{ - var context = this.context; - - // draw triangles!! - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; - var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; - - - context.save(); - context.beginPath(); - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - context.closePath(); - - context.clip(); - - - // Compute matrix transform - var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; - var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; - var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; - var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; - var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; - var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; - var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; - - - - - context.transform(delta_a/delta, delta_d/delta, - delta_b/delta, delta_e/delta, - delta_c/delta, delta_f/delta); - - context.drawImage(strip.texture.baseTexture.source, 0, 0); - context.restore(); - }; - -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A set of functions used by the canvas renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.CanvasGraphics = function() -{ - -} - - -/* - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphics = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); - - context.lineWidth = data.lineWidth; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - - if(data.fillColor || data.fillColor === 0) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); - - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); - } - - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - - }; -} - -/* - * Renders a graphics mask - * - * @static - * @private - * @method renderGraphicsMask - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - var len = graphics.graphicsData.length; - if(len === 0)return; - - if(len > 1) - { - len = 1; - console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") - } - - for (var i=0; i < 1; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - } - else if(data.type == PIXI.Graphics.RECT) - { - context.beginPath(); - context.rect(points[0], points[1], points[2], points[3]); - context.closePath(); - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - } - - - }; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. - * It is important to know that with the webGL renderer only simple polys can be filled at this stage - * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png - * - * @class Graphics - * @extends DisplayObjectContainer - * @constructor - */ -PIXI.Graphics = function() -{ - PIXI.DisplayObjectContainer.call( this ); - - this.renderable = true; - - /** - * The alpha of the fill of this graphics object - * - * @property fillAlpha - * @type Number - */ - this.fillAlpha = 1; - - /** - * The width of any lines drawn - * - * @property lineWidth - * @type Number - */ - this.lineWidth = 0; - - /** - * The color of any lines drawn - * - * @property lineColor - * @type String - */ - this.lineColor = "black"; - - /** - * Graphics data - * - * @property graphicsData - * @type Array - * @private - */ - this.graphicsData = []; - - /** - * Current path - * - * @property currentPath - * @type Object - * @private - */ - this.currentPath = {points:[]}; -} - -// constructor -PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Graphics.prototype.constructor = PIXI.Graphics; - -/** - * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. - * - * @method lineStyle - * @param lineWidth {Number} width of the line to draw, will update the object's stored style - * @param color {Number} color of the line to draw, will update the object's stored style - * @param alpha {Number} alpha of the line to draw, will update the object's stored style - */ -PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.lineWidth = lineWidth || 0; - this.lineColor = color || 0; - this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); -} - -/** - * Moves the current drawing position to (x, y). - * - * @method moveTo - * @param x {Number} the X coord to move to - * @param y {Number} the Y coord to move to - */ -PIXI.Graphics.prototype.moveTo = function(x, y) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.currentPath.points.push(x, y); - - this.graphicsData.push(this.currentPath); -} - -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coord to draw to - * @param y {Number} the Y coord to draw to - */ -PIXI.Graphics.prototype.lineTo = function(x, y) -{ - this.currentPath.points.push(x, y); - this.dirty = true; -} - -/** - * Specifies a simple one-color fill that subsequent calls to other Graphics methods - * (such as lineTo() or drawCircle()) use when drawing. - * - * @method beginFill - * @param color {uint} the color of the fill - * @param alpha {Number} the alpha - */ -PIXI.Graphics.prototype.beginFill = function(color, alpha) -{ - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha == undefined) ? 1 : alpha; -} - -/** - * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. - * - * @method endFill - */ -PIXI.Graphics.prototype.endFill = function() -{ - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; -} - -/** - * @method drawRect - * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle - */ -PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws a circle. - * - * @method drawCircle - * @param x {Number} The X coord of the center of the circle - * @param y {Number} The Y coord of the center of the circle - * @param radius {Number} The radius of the circle - */ -PIXI.Graphics.prototype.drawCircle = function( x, y, radius) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws an elipse. - * - * @method drawElipse - * @param x {Number} - * @param y {Number} - * @param width {Number} - * @param height {Number} - */ -PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. - * - * @method clear - */ -PIXI.Graphics.prototype.clear = function() -{ - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; - - this.bounds = null//new PIXI.Rectangle(); -} - - -PIXI.Graphics.prototype.updateFilterBounds = function() -{ - if(!this.bounds) - { - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - var points, x, y; - - for (var i = 0; i < this.graphicsData.length; i++) { - - - var data = this.graphicsData[i]; - var type = data.type; - var lineWidth = data.lineWidth; - - points = data.points; - - if(type === PIXI.Graphics.RECT) - { - x = points.x - lineWidth/2; - y = points.y - lineWidth/2; - var width = points.width + lineWidth; - var height = points.height + lineWidth; - - minX = x < minX ? x : minX; - maxX = x + width > maxX ? x + width : maxX; - - minY = y < minY ? x : minY; - maxY = y + height > maxY ? y + height : maxY; - } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) - { - x = points.x; - y = points.y; - var radius = points.radius + lineWidth/2; - - minX = x - radius < minX ? x - radius : minX; - maxX = x + radius > maxX ? x + radius : maxX; - - minY = y - radius < minY ? y - radius : minY; - maxY = y + radius > maxY ? y + radius : maxY; - } - else - { - // POLY - for (var j = 0; j < points.length; j+=2) - { - - x = points[j]; - y = points[j+1]; - - minX = x-lineWidth < minX ? x-lineWidth : minX; - maxX = x+lineWidth > maxX ? x+lineWidth : maxX; - - minY = y-lineWidth < minY ? y-lineWidth : minY; - maxY = y+lineWidth > maxY ? y+lineWidth : maxY; - }; - } - - }; - - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); - - } - -// console.log(this.bounds); -} - -// SOME TYPES: -PIXI.Graphics.POLY = 0; -PIXI.Graphics.RECT = 1; -PIXI.Graphics.CIRC = 2; -PIXI.Graphics.ELIP = 3; - -/** - * @author Mat Groves http://matgroves.com/ - */ - -PIXI.Strip = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - this.texture = texture; - this.blendMode = PIXI.blendModes.NORMAL; - - try - { - this.uvs = new Float32Array([0, 1, - 1, 1, - 1, 0, 0,1]); - - this.verticies = new Float32Array([0, 0, - 0,0, - 0,0, 0, - 0, 0]); - - this.colors = new Float32Array([1, 1, 1, 1]); - - this.indices = new Uint16Array([0, 1, 2, 3]); - } - catch(error) - { - this.uvs = [0, 1, - 1, 1, - 1, 0, 0,1]; - - this.verticies = [0, 0, - 0,0, - 0,0, 0, - 0, 0]; - - this.colors = [1, 1, 1, 1]; - - this.indices = [0, 1, 2, 3]; - } - - - /* - this.uvs = new Float32Array() - this.verticies = new Float32Array() - this.colors = new Float32Array() - this.indices = new Uint16Array() -*/ - this.width = width; - this.height = height; - - // load the texture! - if(texture.baseTexture.hasLoaded) - { - this.width = this.texture.frame.width; - this.height = this.texture.frame.height; - this.updateFrame = true; - } - else - { - this.onTextureUpdateBind = this.onTextureUpdate.bind(this); - this.texture.addEventListener( 'update', this.onTextureUpdateBind ); - } - - this.renderable = true; -} - -// constructor -PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Strip.prototype.constructor = PIXI.Strip; - -PIXI.Strip.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.width = texture.frame.width; - this.height = texture.frame.height; - this.updateFrame = true; -} - -PIXI.Strip.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} -// some helper functions.. - - -/** - * @author Mat Groves http://matgroves.com/ - */ - - -PIXI.Rope = function(texture, points) -{ - PIXI.Strip.call( this, texture ); - this.points = points; - - try - { - this.verticies = 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); - } - catch(error) - { - this.verticies = verticies - - this.uvs = uvs - this.colors = colors - this.indices = indices - } - - this.refresh(); -} - - -// constructor -PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); -PIXI.Rope.prototype.constructor = PIXI.Rope; - -PIXI.Rope.prototype.refresh = function() -{ - var points = this.points; - if(points.length < 1)return; - - var uvs = this.uvs - var indices = this.indices; - var colors = this.colors; - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - - uvs[0] = 0 - uvs[1] = 1 - uvs[2] = 0 - uvs[3] = 1 - - colors[0] = 1; - colors[1] = 1; - - indices[0] = 0; - indices[1] = 1; - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - // time to do some smart drawing! - var amount = i/(total-1) - - if(i%2) - { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount - uvs[index+3] = 1 - - } - else - { - uvs[index] = amount - uvs[index+1] = 0 - - uvs[index+2] = amount - uvs[index+3] = 1 - } - - index = i * 2; - colors[index] = 1; - colors[index+1] = 1; - - index = i * 2; - indices[index] = index; - indices[index + 1] = index + 1; - - lastPoint = point; - } -} - -PIXI.Rope.prototype.updateTransform = function() -{ - - var points = this.points; - if(points.length < 1)return; - - var verticies = this.verticies - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - verticies[0] = point.x + perp.x - verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x - verticies[3] = point.y - perp.y//+200 - // time to do some smart drawing! - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - - if(i < points.length-1) - { - nextPoint = points[i+1]; - } - else - { - nextPoint = point - } - - perp.y = -(nextPoint.x - lastPoint.x); - perp.x = nextPoint.y - lastPoint.y; - - var ratio = (1 - (i / (total-1))) * 10; - if(ratio > 1)ratio = 1; - - var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); - var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; - perp.x /= perpLength; - perp.y /= perpLength; - - perp.x *= num; - perp.y *= num; - - verticies[index] = point.x + perp.x - verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x - verticies[index+3] = point.y - perp.y - - lastPoint = point; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); -} - -PIXI.Rope.prototype.setTexture = function(texture) -{ - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * A tiling sprite is a fast way of rendering a tiling image - * - * @class TilingSprite - * @extends DisplayObjectContainer - * @constructor - * @param texture {Texture} the texture of the tiling sprite - * @param width {Number} the width of the tiling sprite - * @param height {Number} the height of the tiling sprite - */ -PIXI.TilingSprite = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * The texture that the sprite is using - * - * @property texture - * @type Texture - */ - this.texture = texture; - - /** - * The width of the tiling sprite - * - * @property width - * @type Number - */ - this.width = width; - - /** - * The height of the tiling sprite - * - * @property height - * @type Number - */ - this.height = height; - - /** - * The scaling of the image that is being tiled - * - * @property tileScale - * @type Point - */ - this.tileScale = new PIXI.Point(1,1); - - /** - * The offset position of the image that is being tiled - * - * @property tilePosition - * @type Point - */ - this.tilePosition = new PIXI.Point(0,0); - - this.renderable = true; - - this.blendMode = PIXI.blendModes.NORMAL -} - -// constructor -PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; - -/** - * Sets the texture of the tiling sprite - * - * @method setTexture - * @param texture {Texture} The PIXI texture that is displayed by the sprite - */ -PIXI.TilingSprite.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - -/** - * When the texture is updated, this event will fire to update the frame - * - * @method onTextureUpdate - * @param event - * @private - */ -PIXI.TilingSprite.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * - * Awesome JS run time provided by EsotericSoftware - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -/** - * A class that enables the you to import and run your spine animations in pixi. - * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * - * @class Spine - * @extends DisplayObjectContainer - * @constructor - * @param url {String} The url of the spine anim file to be used - */ -PIXI.Spine = function (url) { - PIXI.DisplayObjectContainer.call(this); - - this.spineData = PIXI.AnimCache[url]; - - if (!this.spineData) { - throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - } - - this.skeleton = new spine.Skeleton(this.spineData); - this.skeleton.updateWorldTransform(); - - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); - - this.slotContainers = []; - - for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { - var slot = this.skeleton.drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = new PIXI.DisplayObjectContainer(); - this.slotContainers.push(slotContainer); - this.addChild(slotContainer); - if (!(attachment instanceof spine.RegionAttachment)) { - continue; - } - var spriteName = attachment.rendererObject.name; - var sprite = this.createSprite(slot, attachment.rendererObject); - slot.currentSprite = sprite; - slot.currentSpriteName = spriteName; - slotContainer.addChild(sprite); - } -}; - -PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.Spine.prototype.constructor = PIXI.Spine; - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Spine.prototype.updateTransform = function () { - this.lastTime = this.lastTime || Date.now(); - var timeDelta = (Date.now() - this.lastTime) * 0.001; - this.lastTime = Date.now(); - this.state.update(timeDelta); - this.state.apply(this.skeleton); - this.skeleton.updateWorldTransform(); - - var drawOrder = this.skeleton.drawOrder; - for (var i = 0, n = drawOrder.length; i < n; i++) { - var slot = drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = this.slotContainers[i]; - if (!(attachment instanceof spine.RegionAttachment)) { - slotContainer.visible = false; - continue; - } - - if (attachment.rendererObject) { - if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { - var spriteName = attachment.rendererObject.name; - if (slot.currentSprite !== undefined) { - slot.currentSprite.visible = false; - } - slot.sprites = slot.sprites || {}; - if (slot.sprites[spriteName] !== undefined) { - slot.sprites[spriteName].visible = true; - } else { - var sprite = this.createSprite(slot, attachment.rendererObject); - slotContainer.addChild(sprite); - } - slot.currentSprite = slot.sprites[spriteName]; - slot.currentSpriteName = spriteName; - } - } - slotContainer.visible = true; - - var bone = slot.bone; - - slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; - slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; - slotContainer.scale.x = bone.worldScaleX; - slotContainer.scale.y = bone.worldScaleY; - - slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - - -PIXI.Spine.prototype.createSprite = function (slot, descriptor) { - var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); - sprite.scale = descriptor.scale; - sprite.rotation = descriptor.rotation; - sprite.anchor.x = sprite.anchor.y = 0.5; - - slot.sprites = slot.sprites || {}; - slot.sprites[descriptor.name] = sprite; - return sprite; -}; - -/* - * Awesome JS run time provided by EsotericSoftware - * - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -var spine = {}; - -spine.BoneData = function (name, parent) { - this.name = name; - this.parent = parent; -}; -spine.BoneData.prototype = { - length: 0, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1 -}; - -spine.SlotData = function (name, boneData) { - this.name = name; - this.boneData = boneData; -}; -spine.SlotData.prototype = { - r: 1, g: 1, b: 1, a: 1, - attachmentName: null -}; - -spine.Bone = function (boneData, parent) { - this.data = boneData; - this.parent = parent; - this.setToSetupPose(); -}; -spine.Bone.yDown = false; -spine.Bone.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - m00: 0, m01: 0, worldX: 0, // a b x - m10: 0, m11: 0, worldY: 0, // c d y - worldRotation: 0, - worldScaleX: 1, worldScaleY: 1, - updateWorldTransform: function (flipX, flipY) { - var parent = this.parent; - if (parent != null) { - this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; - this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; - this.worldScaleX = parent.worldScaleX * this.scaleX; - this.worldScaleY = parent.worldScaleY * this.scaleY; - this.worldRotation = parent.worldRotation + this.rotation; - } else { - this.worldX = this.x; - this.worldY = this.y; - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - this.worldRotation = this.rotation; - } - var radians = this.worldRotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - this.m00 = cos * this.worldScaleX; - this.m10 = sin * this.worldScaleX; - this.m01 = -sin * this.worldScaleY; - this.m11 = cos * this.worldScaleY; - if (flipX) { - this.m00 = -this.m00; - this.m01 = -this.m01; - } - if (flipY) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - if (spine.Bone.yDown) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - }, - setToSetupPose: function () { - var data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - } -}; - -spine.Slot = function (slotData, skeleton, bone) { - this.data = slotData; - this.skeleton = skeleton; - this.bone = bone; - this.setToSetupPose(); -}; -spine.Slot.prototype = { - r: 1, g: 1, b: 1, a: 1, - _attachmentTime: 0, - attachment: null, - setAttachment: function (attachment) { - this.attachment = attachment; - this._attachmentTime = this.skeleton.time; - }, - setAttachmentTime: function (time) { - this._attachmentTime = this.skeleton.time - time; - }, - getAttachmentTime: function () { - return this.skeleton.time - this._attachmentTime; - }, - setToSetupPose: function () { - var data = this.data; - this.r = data.r; - this.g = data.g; - this.b = data.b; - this.a = data.a; - - var slotDatas = this.skeleton.data.slots; - for (var i = 0, n = slotDatas.length; i < n; i++) { - if (slotDatas[i] == data) { - this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); - break; - } - } - } -}; - -spine.Skin = function (name) { - this.name = name; - this.attachments = {}; -}; -spine.Skin.prototype = { - addAttachment: function (slotIndex, name, attachment) { - this.attachments[slotIndex + ":" + name] = attachment; - }, - getAttachment: function (slotIndex, name) { - return this.attachments[slotIndex + ":" + name]; - }, - _attachAll: function (skeleton, oldSkin) { - for (var key in oldSkin.attachments) { - var colon = key.indexOf(":"); - var slotIndex = parseInt(key.substring(0, colon)); - var name = key.substring(colon + 1); - var slot = skeleton.slots[slotIndex]; - if (slot.attachment && slot.attachment.name == name) { - var attachment = this.getAttachment(slotIndex, name); - if (attachment) slot.setAttachment(attachment); - } - } - } -}; - -spine.Animation = function (name, timelines, duration) { - this.name = name; - this.timelines = timelines; - this.duration = duration; -}; -spine.Animation.prototype = { - apply: function (skeleton, time, loop) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, 1); - }, - mix: function (skeleton, time, loop, alpha) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, alpha); - } -}; - -spine.binarySearch = function (values, target, step) { - var low = 0; - var high = Math.floor(values.length / step) - 2; - if (high == 0) return step; - var current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } -}; -spine.linearSearch = function (values, target, step) { - for (var i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; -}; - -spine.Curves = function (frameCount) { - this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... - this.curves.length = (frameCount - 1) * 6; -}; -spine.Curves.prototype = { - setLinear: function (frameIndex) { - this.curves[frameIndex * 6] = 0/*LINEAR*/; - }, - setStepped: function (frameIndex) { - this.curves[frameIndex * 6] = -1/*STEPPED*/; - }, - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { - var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; - var subdiv_step2 = subdiv_step * subdiv_step; - var subdiv_step3 = subdiv_step2 * subdiv_step; - var pre1 = 3 * subdiv_step; - var pre2 = 3 * subdiv_step2; - var pre4 = 6 * subdiv_step2; - var pre5 = 6 * subdiv_step3; - var tmp1x = -cx1 * 2 + cx2; - var tmp1y = -cy1 * 2 + cy2; - var tmp2x = (cx1 - cx2) * 3 + 1; - var tmp2y = (cy1 - cy2) * 3 + 1; - var i = frameIndex * 6; - var curves = this.curves; - curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; - curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; - curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; - curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; - curves[i + 4] = tmp2x * pre5; - curves[i + 5] = tmp2y * pre5; - }, - getCurvePercent: function (frameIndex, percent) { - percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); - var curveIndex = frameIndex * 6; - var curves = this.curves; - var dfx = curves[curveIndex]; - if (!dfx/*LINEAR*/) return percent; - if (dfx == -1/*STEPPED*/) return 0; - var dfy = curves[curveIndex + 1]; - var ddfx = curves[curveIndex + 2]; - var ddfy = curves[curveIndex + 3]; - var dddfx = curves[curveIndex + 4]; - var dddfy = curves[curveIndex + 5]; - var x = dfx, y = dfy; - var i = 10/*BEZIER_SEGMENTS*/ - 2; - while (true) { - if (x >= percent) { - var lastX = x - dfx; - var lastY = y - dfy; - return lastY + (y - lastY) * (percent - lastX) / (x - lastX); - } - if (i == 0) break; - i--; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -}; - -spine.RotateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, angle, ... - this.frames.length = frameCount * 2; -}; -spine.RotateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, angle) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = angle; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 2]) { // Time is after last frame. - var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 2); - var lastFrameValue = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); - - var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -}; - -spine.TranslateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.TranslateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; - } -}; - -spine.ScaleTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.ScaleTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; - } -}; - -spine.ColorTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, r, g, b, a, ... - this.frames.length = frameCount * 5; -}; -spine.ColorTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 5; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = r; - this.frames[frameIndex + 2] = g; - this.frames[frameIndex + 3] = b; - this.frames[frameIndex + 4] = a; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var slot = skeleton.slots[this.slotIndex]; - - if (time >= frames[frames.length - 5]) { // Time is after last frame. - var i = frames.length - 1; - slot.r = frames[i - 3]; - slot.g = frames[i - 2]; - slot.b = frames[i - 1]; - slot.a = frames[i]; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 5); - var lastFrameR = frames[frameIndex - 4]; - var lastFrameG = frames[frameIndex - 3]; - var lastFrameB = frames[frameIndex - 2]; - var lastFrameA = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); - - var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; - var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; - var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; - var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -}; - -spine.AttachmentTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, ... - this.frames.length = frameCount; - this.attachmentNames = []; // time, ... - this.attachmentNames.length = frameCount; -}; -spine.AttachmentTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, attachmentName) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = spine.binarySearch(frames, time, 1) - 1; - - var attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); - } -}; - -spine.SkeletonData = function () { - this.bones = []; - this.slots = []; - this.skins = []; - this.animations = []; -}; -spine.SkeletonData.prototype = { - defaultSkin: null, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - if (slots[i].name == slotName) return slot[i]; - } - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - }, - /** @return May be null. */ - findSkin: function (skinName) { - var skins = this.skins; - for (var i = 0, n = skins.length; i < n; i++) - if (skins[i].name == skinName) return skins[i]; - return null; - }, - /** @return May be null. */ - findAnimation: function (animationName) { - var animations = this.animations; - for (var i = 0, n = animations.length; i < n; i++) - if (animations[i].name == animationName) return animations[i]; - return null; - } -}; - -spine.Skeleton = function (skeletonData) { - this.data = skeletonData; - - this.bones = []; - for (var i = 0, n = skeletonData.bones.length; i < n; i++) { - var boneData = skeletonData.bones[i]; - var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; - this.bones.push(new spine.Bone(boneData, parent)); - } - - this.slots = []; - this.drawOrder = []; - for (var i = 0, n = skeletonData.slots.length; i < n; i++) { - var slotData = skeletonData.slots[i]; - var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; - var slot = new spine.Slot(slotData, this, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } -}; -spine.Skeleton.prototype = { - x: 0, y: 0, - skin: null, - r: 1, g: 1, b: 1, a: 1, - time: 0, - flipX: false, flipY: false, - /** Updates the world transform for each bone. */ - updateWorldTransform: function () { - var flipX = this.flipX; - var flipY = this.flipY; - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].updateWorldTransform(flipX, flipY); - }, - /** Sets the bones and slots to their setup pose values. */ - setToSetupPose: function () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - }, - setBonesToSetupPose: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - }, - setSlotsToSetupPose: function () { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - slots[i].setToSetupPose(i); - }, - /** @return May return null. */ - getRootBone: function () { - return this.bones.length == 0 ? null : this.bones[0]; - }, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return slots[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - }, - setSkinByName: function (skinName) { - var skin = this.data.findSkin(skinName); - if (!skin) throw "Skin not found: " + skinName; - this.setSkin(skin); - }, - /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments - * from the new skin are attached if the corresponding attachment from the old skin was attached. - * @param newSkin May be null. */ - setSkin: function (newSkin) { - if (this.skin && newSkin) newSkin._attachAll(this, this.skin); - this.skin = newSkin; - }, - /** @return May be null. */ - getAttachmentBySlotName: function (slotName, attachmentName) { - return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); - }, - /** @return May be null. */ - getAttachmentBySlotIndex: function (slotIndex, attachmentName) { - if (this.skin) { - var attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment) return attachment; - } - if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - }, - /** @param attachmentName May be null. */ - setAttachment: function (slotName, attachmentName) { - var slots = this.slots; - for (var i = 0, n = slots.size; i < n; i++) { - var slot = slots[i]; - if (slot.data.name == slotName) { - var attachment = null; - if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); - if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; - } - slot.setAttachment(attachment); - return; - } - } - throw "Slot not found: " + slotName; - }, - update: function (delta) { - time += delta; - } -}; - -spine.AttachmentType = { - region: 0 -}; - -spine.RegionAttachment = function () { - this.offset = []; - this.offset.length = 8; - this.uvs = []; - this.uvs.length = 8; -}; -spine.RegionAttachment.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - width: 0, height: 0, - rendererObject: null, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - setUVs: function (u, v, u2, v2, rotate) { - var uvs = this.uvs; - if (rotate) { - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v2; - uvs[4/*X3*/] = u; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v; - uvs[0/*X1*/] = u2; - uvs[1/*Y1*/] = v2; - } else { - uvs[0/*X1*/] = u; - uvs[1/*Y1*/] = v2; - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v; - uvs[4/*X3*/] = u2; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v2; - } - }, - updateOffset: function () { - var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; - var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; - var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; - var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; - var localX2 = localX + this.regionWidth * regionScaleX; - var localY2 = localY + this.regionHeight * regionScaleY; - var radians = this.rotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var localXCos = localX * cos + this.x; - var localXSin = localX * sin; - var localYCos = localY * cos + this.y; - var localYSin = localY * sin; - var localX2Cos = localX2 * cos + this.x; - var localX2Sin = localX2 * sin; - var localY2Cos = localY2 * cos + this.y; - var localY2Sin = localY2 * sin; - var offset = this.offset; - offset[0/*X1*/] = localXCos - localYSin; - offset[1/*Y1*/] = localYCos + localXSin; - offset[2/*X2*/] = localXCos - localY2Sin; - offset[3/*Y2*/] = localY2Cos + localXSin; - offset[4/*X3*/] = localX2Cos - localY2Sin; - offset[5/*Y3*/] = localY2Cos + localX2Sin; - offset[6/*X4*/] = localX2Cos - localYSin; - offset[7/*Y4*/] = localYCos + localX2Sin; - }, - computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00; - var m01 = bone.m01; - var m10 = bone.m10; - var m11 = bone.m11; - var offset = this.offset; - vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; - vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; - vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; - vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; - vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; - vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; - vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; - vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; - } -} - -spine.AnimationStateData = function (skeletonData) { - this.skeletonData = skeletonData; - this.animationToMixTime = {}; -}; -spine.AnimationStateData.prototype = { - defaultMix: 0, - setMixByName: function (fromName, toName, duration) { - var from = this.skeletonData.findAnimation(fromName); - if (!from) throw "Animation not found: " + fromName; - var to = this.skeletonData.findAnimation(toName); - if (!to) throw "Animation not found: " + toName; - this.setMix(from, to, duration); - }, - setMix: function (from, to, duration) { - this.animationToMixTime[from.name + ":" + to.name] = duration; - }, - getMix: function (from, to) { - var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : this.defaultMix; - } -}; - -spine.AnimationState = function (stateData) { - this.data = stateData; - this.queue = []; -}; -spine.AnimationState.prototype = { - current: null, - previous: null, - currentTime: 0, - previousTime: 0, - currentLoop: false, - previousLoop: false, - mixTime: 0, - mixDuration: 0, - update: function (delta) { - this.currentTime += delta; - this.previousTime += delta; - this.mixTime += delta; - - if (this.queue.length > 0) { - var entry = this.queue[0]; - if (this.currentTime >= entry.delay) { - this._setAnimation(entry.animation, entry.loop); - this.queue.shift(); - } - } - }, - apply: function (skeleton) { - if (!this.current) return; - if (this.previous) { - this.previous.apply(skeleton, this.previousTime, this.previousLoop); - var alpha = this.mixTime / this.mixDuration; - if (alpha >= 1) { - alpha = 1; - this.previous = null; - } - this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else - this.current.apply(skeleton, this.currentTime, this.currentLoop); - }, - clearAnimation: function () { - this.previous = null; - this.current = null; - this.queue.length = 0; - }, - _setAnimation: function (animation, loop) { - this.previous = null; - if (animation && this.current) { - this.mixDuration = this.data.getMix(this.current, animation); - if (this.mixDuration > 0) { - this.mixTime = 0; - this.previous = this.current; - this.previousTime = this.currentTime; - this.previousLoop = this.currentLoop; - } - } - this.current = animation; - this.currentLoop = loop; - this.currentTime = 0; - }, - /** @see #setAnimation(Animation, Boolean) */ - setAnimationByName: function (animationName, loop) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.setAnimation(animation, loop); - }, - /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. - * @param animation May be null. */ - setAnimation: function (animation, loop) { - this.queue.length = 0; - this._setAnimation(animation, loop); - }, - /** @see #addAnimation(Animation, Boolean, Number) */ - addAnimationByName: function (animationName, loop, delay) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.addAnimation(animation, loop, delay); - }, - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimation: function (animation, loop, delay) { - var entry = {}; - entry.animation = animation; - entry.loop = loop; - - if (!delay || delay <= 0) { - var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; - if (previousAnimation != null) - delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); - else - delay = 0; - } - entry.delay = delay; - - this.queue.push(entry); - }, - /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ - isComplete: function () { - return !this.current || this.currentTime >= this.current.duration; - } -}; - -spine.SkeletonJson = function (attachmentLoader) { - this.attachmentLoader = attachmentLoader; -}; -spine.SkeletonJson.prototype = { - scale: 1, - readSkeletonData: function (root) { - var skeletonData = new spine.SkeletonData(); - - // Bones. - var bones = root["bones"]; - for (var i = 0, n = bones.length; i < n; i++) { - var boneMap = bones[i]; - var parent = null; - if (boneMap["parent"]) { - parent = skeletonData.findBone(boneMap["parent"]); - if (!parent) throw "Parent bone not found: " + boneMap["parent"]; - } - var boneData = new spine.BoneData(boneMap["name"], parent); - boneData.length = (boneMap["length"] || 0) * this.scale; - boneData.x = (boneMap["x"] || 0) * this.scale; - boneData.y = (boneMap["y"] || 0) * this.scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap["scaleX"] || 1; - boneData.scaleY = boneMap["scaleY"] || 1; - skeletonData.bones.push(boneData); - } - - // Slots. - var slots = root["slots"]; - for (var i = 0, n = slots.length; i < n; i++) { - var slotMap = slots[i]; - var boneData = skeletonData.findBone(slotMap["bone"]); - if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; - var slotData = new spine.SlotData(slotMap["name"], boneData); - - var color = slotMap["color"]; - if (color) { - slotData.r = spine.SkeletonJson.toColor(color, 0); - slotData.g = spine.SkeletonJson.toColor(color, 1); - slotData.b = spine.SkeletonJson.toColor(color, 2); - slotData.a = spine.SkeletonJson.toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - - skeletonData.slots.push(slotData); - } - - // Skins. - var skins = root["skins"]; - for (var skinName in skins) { - if (!skins.hasOwnProperty(skinName)) continue; - var skinMap = skins[skinName]; - var skin = new spine.Skin(skinName); - for (var slotName in skinMap) { - if (!skinMap.hasOwnProperty(slotName)) continue; - var slotIndex = skeletonData.findSlotIndex(slotName); - var slotEntry = skinMap[slotName]; - for (var attachmentName in slotEntry) { - if (!slotEntry.hasOwnProperty(attachmentName)) continue; - var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); - if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - - // Animations. - var animations = root["animations"]; - for (var animationName in animations) { - if (!animations.hasOwnProperty(animationName)) continue; - this.readAnimation(animationName, animations[animationName], skeletonData); - } - - return skeletonData; - }, - readAttachment: function (skin, name, map) { - name = map["name"] || name; - - var type = spine.AttachmentType[map["type"] || "region"]; - - if (type == spine.AttachmentType.region) { - var attachment = new spine.RegionAttachment(); - attachment.x = (map["x"] || 0) * this.scale; - attachment.y = (map["y"] || 0) * this.scale; - attachment.scaleX = map["scaleX"] || 1; - attachment.scaleY = map["scaleY"] || 1; - attachment.rotation = map["rotation"] || 0; - attachment.width = (map["width"] || 32) * this.scale; - attachment.height = (map["height"] || 32) * this.scale; - attachment.updateOffset(); - - attachment.rendererObject = {}; - attachment.rendererObject.name = name; - attachment.rendererObject.scale = {}; - attachment.rendererObject.scale.x = attachment.scaleX; - attachment.rendererObject.scale.y = attachment.scaleY; - attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; - return attachment; - } - - throw "Unknown attachment type: " + type; - }, - - readAnimation: function (name, map, skeletonData) { - var timelines = []; - var duration = 0; - - var bones = map["bones"]; - for (var boneName in bones) { - if (!bones.hasOwnProperty(boneName)) continue; - var boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw "Bone not found: " + boneName; - var boneMap = bones[boneName]; - - for (var timelineName in boneMap) { - if (!boneMap.hasOwnProperty(timelineName)) continue; - var values = boneMap[timelineName]; - if (timelineName == "rotate") { - var timeline = new spine.RotateTimeline(values.length); - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - - } else if (timelineName == "translate" || timelineName == "scale") { - var timeline; - var timelineScale = 1; - if (timelineName == "scale") - timeline = new spine.ScaleTimeline(values.length); - else { - timeline = new spine.TranslateTimeline(values.length); - timelineScale = this.scale; - } - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var x = (valueMap["x"] || 0) * timelineScale; - var y = (valueMap["y"] || 0) * timelineScale; - timeline.setFrame(frameIndex, valueMap["time"], x, y); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - - } else - throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; - } - } - var slots = map["slots"]; - for (var slotName in slots) { - if (!slots.hasOwnProperty(slotName)) continue; - var slotMap = slots[slotName]; - var slotIndex = skeletonData.findSlotIndex(slotName); - - for (var timelineName in slotMap) { - if (!slotMap.hasOwnProperty(timelineName)) continue; - var values = slotMap[timelineName]; - if (timelineName == "color") { - var timeline = new spine.ColorTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var color = valueMap["color"]; - var r = spine.SkeletonJson.toColor(color, 0); - var g = spine.SkeletonJson.toColor(color, 1); - var b = spine.SkeletonJson.toColor(color, 2); - var a = spine.SkeletonJson.toColor(color, 3); - timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); - - } else if (timelineName == "attachment") { - var timeline = new spine.AttachmentTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - - } else - throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; - } - } - skeletonData.animations.push(new spine.Animation(name, timelines, duration)); - } -}; -spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { - var curve = valueMap["curve"]; - if (!curve) return; - if (curve == "stepped") - timeline.curves.setStepped(frameIndex); - else if (curve instanceof Array) - timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); -}; -spine.SkeletonJson.toColor = function (hexString, colorIndex) { - if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; - return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; -}; - -spine.Atlas = function (atlasText, textureLoader) { - this.textureLoader = textureLoader; - this.pages = []; - this.regions = []; - - var reader = new spine.AtlasReader(atlasText); - var tuple = []; - tuple.length = 4; - var page = null; - while (true) { - var line = reader.readLine(); - if (line == null) break; - line = reader.trim(line); - if (line.length == 0) - page = null; - else if (!page) { - page = new spine.AtlasPage(); - page.name = line; - - page.format = spine.Atlas.Format[reader.readValue()]; - - reader.readTuple(tuple); - page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; - page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; - - var direction = reader.readValue(); - page.uWrap = spine.Atlas.TextureWrap.clampToEdge; - page.vWrap = spine.Atlas.TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "y") - page.vWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; - - textureLoader.load(page, line); - - this.pages.push(page); - - } else { - var region = new spine.AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x = parseInt(tuple[0]); - var y = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width = parseInt(tuple[0]); - var height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - this.regions.push(region); - } - } -}; -spine.Atlas.prototype = { - findRegion: function (name) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - }, - dispose: function () { - var pages = this.pages; - for (var i = 0, n = pages.length; i < n; i++) - this.textureLoader.unload(pages[i].rendererObject); - }, - updateUVs: function (page) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) { - var region = regions[i]; - if (region.page != page) continue; - region.u = region.x / page.width; - region.v = region.y / page.height; - if (region.rotate) { - region.u2 = (region.x + region.height) / page.width; - region.v2 = (region.y + region.width) / page.height; - } else { - region.u2 = (region.x + region.width) / page.width; - region.v2 = (region.y + region.height) / page.height; - } - } - } -}; - -spine.Atlas.Format = { - alpha: 0, - intensity: 1, - luminanceAlpha: 2, - rgb565: 3, - rgba4444: 4, - rgb888: 5, - rgba8888: 6 -}; - -spine.Atlas.TextureFilter = { - nearest: 0, - linear: 1, - mipMap: 2, - mipMapNearestNearest: 3, - mipMapLinearNearest: 4, - mipMapNearestLinear: 5, - mipMapLinearLinear: 6 -}; - -spine.Atlas.TextureWrap = { - mirroredRepeat: 0, - clampToEdge: 1, - repeat: 2 -}; - -spine.AtlasPage = function () {}; -spine.AtlasPage.prototype = { - name: null, - format: null, - minFilter: null, - magFilter: null, - uWrap: null, - vWrap: null, - rendererObject: null, - width: 0, - height: 0 -}; - -spine.AtlasRegion = function () {}; -spine.AtlasRegion.prototype = { - page: null, - name: null, - x: 0, y: 0, - width: 0, height: 0, - u: 0, v: 0, u2: 0, v2: 0, - offsetX: 0, offsetY: 0, - originalWidth: 0, originalHeight: 0, - index: 0, - rotate: false, - splits: null, - pads: null, -}; - -spine.AtlasReader = function (text) { - this.lines = text.split(/\r\n|\r|\n/); -}; -spine.AtlasReader.prototype = { - index: 0, - trim: function (value) { - return value.replace(/^\s+|\s+$/g, ""); - }, - readLine: function () { - if (this.index >= this.lines.length) return null; - return this.lines[this.index++]; - }, - readValue: function () { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - return this.trim(line.substring(colon + 1)); - }, - /** Returns the number of tuple values read (2 or 4). */ - readTuple: function (tuple) { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - var i = 0, lastMatch= colon + 1; - for (; i < 3; i++) { - var comma = line.indexOf(",", lastMatch); - if (comma == -1) { - if (i == 0) throw "Invalid line: " + line; - break; - } - tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = this.trim(line.substring(lastMatch)); - return i + 1; - } -} - -spine.AtlasAttachmentLoader = function (atlas) { - this.atlas = atlas; -} -spine.AtlasAttachmentLoader.prototype = { - newAttachment: function (skin, type, name) { - switch (type) { - case spine.AttachmentType.region: - var region = this.atlas.findRegion(name); - if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; - var attachment = new spine.RegionAttachment(name); - attachment.rendererObject = region; - attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - throw "Unknown attachment type: " + type; - } -} - -PIXI.AnimCache = {}; -spine.Bone.yDown = true; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * This object is one that will allow you to specify custom rendering functions based on render type - * - * @class CustomRenderable - * @extends DisplayObject - * @constructor - */ -PIXI.CustomRenderable = function() -{ - PIXI.DisplayObject.call( this ); - - this.renderable = true; -} - -// constructor -PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; - -/** - * If this object is being rendered by a CanvasRenderer it will call this callback - * - * @method renderCanvas - * @param renderer {CanvasRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback to initialize - * - * @method initWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.initWebGL = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback - * - * @method renderWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) -{ - // not sure if both needed? but ya have for now! - // override! -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; - -/** - * A texture stores the information that represents an image. All textures have a base texture - * - * @class BaseTexture - * @uses EventTarget - * @constructor - * @param source {String} the source object (image or canvas) - */ -PIXI.BaseTexture = function(source) -{ - PIXI.EventTarget.call( this ); - - /** - * [read-only] The width of the base texture set when the image has loaded - * - * @property width - * @type Number - * @readOnly - */ - this.width = 100; - - /** - * [read-only] The height of the base texture set when the image has loaded - * - * @property height - * @type Number - * @readOnly - */ - this.height = 100; - - /** - * [read-only] Describes if the base texture has loaded or not - * - * @property hasLoaded - * @type Boolean - * @readOnly - */ - this.hasLoaded = false; - - /** - * The source that is loaded to create the texture - * - * @property source - * @type Image - */ - this.source = source; - - if(!source)return; - - if(this.source instanceof Image || this.source instanceof HTMLImageElement) - { - if(this.source.complete) - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - else - { - - var scope = this; - this.source.onload = function(){ - - scope.hasLoaded = true; - scope.width = scope.source.width; - scope.height = scope.source.height; - - // add it to somewhere... - PIXI.texturesToUpdate.push(scope); - scope.dispatchEvent( { type: 'loaded', content: scope } ); - } - // this.image.src = imageUrl; - } - } - else - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - - this._powerOf2 = false; -} - -PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; - -/** - * Destroys this base texture - * - * @method destroy - */ -PIXI.BaseTexture.prototype.destroy = function() -{ - if(this.source instanceof Image) - { - this.source.src = null; - } - this.source = null; - PIXI.texturesToDestroy.push(this); -} - -/** - * Helper function that returns a base texture based on an image url - * If the image is not in the base texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @return BaseTexture - */ -PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) -{ - var baseTexture = PIXI.BaseTextureCache[imageUrl]; - if(!baseTexture) - { - // new Image() breaks tex loading in some versions of Chrome. - // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); - if (crossorigin) - { - image.crossOrigin = ''; - } - image.src = imageUrl; - baseTexture = new PIXI.BaseTexture(image); - PIXI.BaseTextureCache[imageUrl] = baseTexture; - } - - return baseTexture; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.TextureCache = {}; -PIXI.FrameCache = {}; - -/** - * A texture stores the information that represents an image or part of an image. It cannot be added - * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used - * - * @class Texture - * @uses EventTarget - * @constructor - * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frame {Rectangle} The rectangle frame of the texture to show - */ -PIXI.Texture = function(baseTexture, frame) -{ - PIXI.EventTarget.call( this ); - - if(!frame) - { - this.noFrame = true; - frame = new PIXI.Rectangle(0,0,1,1); - } - - if(baseTexture instanceof PIXI.Texture) - baseTexture = baseTexture.baseTexture; - - /** - * The base texture of this texture - * - * @property baseTexture - * @type BaseTexture - */ - this.baseTexture = baseTexture; - - /** - * The frame specifies the region of the base texture that this texture uses - * - * @property frame - * @type Rectangle - */ - this.frame = frame; - - /** - * The trim point - * - * @property trim - * @type Point - */ - this.trim = new PIXI.Point(); - - this.scope = this; - - if(baseTexture.hasLoaded) - { - if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - //console.log(frame) - - this.setFrame(frame); - } - else - { - var scope = this; - baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); - } -} - -PIXI.Texture.prototype.constructor = PIXI.Texture; - -/** - * Called when the base texture is loaded - * - * @method onBaseTextureLoaded - * @param event - * @private - */ -PIXI.Texture.prototype.onBaseTextureLoaded = function(event) -{ - var baseTexture = this.baseTexture; - baseTexture.removeEventListener( 'loaded', this.onLoaded ); - - if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - this.noFrame = false; - this.width = this.frame.width; - this.height = this.frame.height; - - this.scope.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Destroys this texture - * - * @method destroy - * @param destroyBase {Boolean} Whether to destroy the base texture as well - */ -PIXI.Texture.prototype.destroy = function(destroyBase) -{ - if(destroyBase)this.baseTexture.destroy(); -} - -/** - * Specifies the rectangle region of the baseTexture - * - * @method setFrame - * @param frame {Rectangle} The frame of the texture to set it to - */ -PIXI.Texture.prototype.setFrame = function(frame) -{ - this.frame = frame; - this.width = frame.width; - this.height = frame.height; - - 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); - } - - this.updateFrame = true; - - PIXI.Texture.frameUpdates.push(this); - //this.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Helper function that returns a texture based on an image url - * If the image is not in the texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - * @return Texture - */ -PIXI.Texture.fromImage = function(imageUrl, crossorigin) -{ - var texture = PIXI.TextureCache[imageUrl]; - - if(!texture) - { - texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); - PIXI.TextureCache[imageUrl] = texture; - } - - return texture; -} - -/** - * Helper function that returns a texture based on a frame id - * If the frame id is not in the texture cache an error will be thrown - * - * @static - * @method fromFrame - * @param frameId {String} The frame id of the texture - * @return Texture - */ -PIXI.Texture.fromFrame = function(frameId) -{ - var texture = PIXI.TextureCache[frameId]; - if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); - return texture; -} - -/** - * Helper function that returns a texture based on a canvas element - * If the canvas is not in the texture cache it will be created and loaded - * - * @static - * @method fromCanvas - * @param canvas {Canvas} The canvas element source of the texture - * @return Texture - */ -PIXI.Texture.fromCanvas = function(canvas) -{ - var baseTexture = new PIXI.BaseTexture(canvas); - return new PIXI.Texture(baseTexture); -} - - -/** - * Adds a texture to the textureCache. - * - * @static - * @method addTextureToCache - * @param texture {Texture} - * @param id {String} the id that the texture will be stored against. - */ -PIXI.Texture.addTextureToCache = function(texture, id) -{ - PIXI.TextureCache[id] = texture; -} - -/** - * Remove a texture from the textureCache. - * - * @static - * @method removeTextureFromCache - * @param id {String} the id of the texture to be removed - * @return {Texture} the texture that was removed - */ -PIXI.Texture.removeTextureFromCache = function(id) -{ - var texture = PIXI.TextureCache[id] - PIXI.TextureCache[id] = null; - return texture; -} - -// this is more for webGL.. it contains updated frames.. -PIXI.Texture.frameUpdates = []; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. - - __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. - Otherwise black rectangles will be drawn instead. - - RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: - - var renderTexture = new PIXI.RenderTexture(800, 600); - var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); - sprite.position.x = 800/2; - sprite.position.y = 600/2; - sprite.anchor.x = 0.5; - sprite.anchor.y = 0.5; - renderTexture.render(sprite); - - Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: - - var doc = new PIXI.DisplayObjectContainer(); - doc.addChild(sprite); - renderTexture.render(doc); // Renders to center of renderTexture - - @class RenderTexture - @extends Texture - @constructor - @param width {Number} The width of the render texture - @param height {Number} The height of the render texture - */ -PIXI.RenderTexture = function(width, height) -{ - PIXI.EventTarget.call( this ); - - this.width = width || 100; - this.height = height || 100; - - this.indetityMatrix = PIXI.mat3.create(); - - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - if(PIXI.gl) - { - this.initWebGL(); - } - else - { - this.initCanvas(); - } -} - -PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); -PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; - -/** - * Initializes the webgl data for this texture - * - * @method initWebGL - * @private - */ -PIXI.RenderTexture.prototype.initWebGL = function() -{ - var gl = PIXI.gl; - this.glFramebuffer = gl.createFramebuffer(); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - this.glFramebuffer.width = this.width; - this.glFramebuffer.height = this.height; - - this.baseTexture = new PIXI.BaseTexture(); - - this.baseTexture.width = this.width; - this.baseTexture.height = this.height; - - this.baseTexture._glTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - - this.baseTexture.isRender = true; - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); - - // create a projection matrix.. - this.projection = new PIXI.Point(this.width/2 , -this.height/2); - - // set the correct render function.. - this.render = this.renderWebGL; -} - - -PIXI.RenderTexture.prototype.resize = function(width, height) -{ - - this.width = width; - this.height = height; - - if(PIXI.gl) - { - this.projection.x = this.width/2 - this.projection.y = -this.height/2; - - var gl = PIXI.gl; - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - } - else - { - - this.frame.width = this.width - this.frame.height = this.height; - this.renderer.resize(this.width, this.height); - } -} - -/** - * Initializes the canvas data for this texture - * - * @method initCanvas - * @private - */ -PIXI.RenderTexture.prototype.initCanvas = function() -{ - this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); - - this.baseTexture = new PIXI.BaseTexture(this.renderer.view); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - this.render = this.renderCanvas; -} - -/** - * This function will draw the display object to the texture. - * - * @method renderWebGL - * @param displayObject {DisplayObject} The display object to render this texture on - * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn - * @private - */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) -{ - var gl = PIXI.gl; - - // enable the alpha color mask.. - gl.colorMask(true, true, true, true); - - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - if(clear) - { - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } - - // THIS WILL MESS WITH HIT TESTING! - var children = displayObject.children; - - //TODO -? create a new one??? dont think so! - var originalWorldTransform = displayObject.worldTransform; - displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; - // modify to flip... - displayObject.worldTransform[4] = -1; - displayObject.worldTransform[5] = this.projection.y * -2; - - if(position) - { - displayObject.worldTransform[2] = position.x; - displayObject.worldTransform[5] -= position.y; - } - - PIXI.visibleCount++; - displayObject.vcount = PIXI.visibleCount; - - for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded - * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported - * sprite sheet data formats only include "JSON" at this time. Supported bitmap font - * data formats include "xml" and "fnt". - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.AssetLoader = function(assetURLs, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The array of asset URLs that are going to be loaded - * - * @property assetURLs - * @type Array - */ - this.assetURLs = assetURLs; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * Maps file extension to loader types - * - * @property loadersByType - * @type Object - */ - this.loadersByType = { - "jpg": PIXI.ImageLoader, - "jpeg": PIXI.ImageLoader, - "png": PIXI.ImageLoader, - "gif": PIXI.ImageLoader, - "json": PIXI.JsonLoader, - "anim": PIXI.SpineLoader, - "xml": PIXI.BitmapFontLoader, - "fnt": PIXI.BitmapFontLoader - }; - - -}; - -/** - * Fired when an item has loaded - * @event onProgress - */ - -/** - * Fired when all the assets have loaded - * @event onComplete - */ - -// constructor -PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; - -/** - * Starts loading the assets sequentially - * - * @method load - */ -PIXI.AssetLoader.prototype.load = function() -{ - var scope = this; - - this.loadCount = this.assetURLs.length; - - for (var i=0; i < this.assetURLs.length; i++) - { - var fileName = this.assetURLs[i]; - var fileType = fileName.split(".").pop().toLowerCase(); - - var loaderClass = this.loadersByType[fileType]; - if(!loaderClass) - throw new Error(fileType + " is an unsupported file type"); - - var loader = new loaderClass(fileName, this.crossorigin); - - loader.addEventListener("loaded", function() - { - scope.onAssetLoaded(); - }); - loader.load(); - } -}; - -/** - * Invoked after each file is loaded - * - * @method onAssetLoaded - * @private - */ -PIXI.AssetLoader.prototype.onAssetLoaded = function() -{ - this.loadCount--; - this.dispatchEvent({type: "onProgress", content: this}); - if(this.onProgress) this.onProgress(); - - if(this.loadCount == 0) - { - this.dispatchEvent({type: "onComplete", content: this}); - if(this.onComplete) this.onComplete(); - } -}; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The json file loader is used to load in JSON data and parsing it - * When loaded this class will dispatch a "loaded" event - * If load failed this class will dispatch a "error" event - * - * @class JsonLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.JsonLoader = function (url, crossorigin) { - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * [read-only] Whether the data has loaded yet - * - * @property loaded - * @type Boolean - * @readOnly - */ - this.loaded = false; - -}; - -// constructor -PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; - -/** - * Loads the JSON data - * - * @method load - */ -PIXI.JsonLoader.prototype.load = function () { - this.ajaxRequest = new AjaxRequest(); - var scope = this; - this.ajaxRequest.onreadystatechange = function () { - scope.onJSONLoaded(); - }; - - this.ajaxRequest.open("GET", this.url, true); - if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); - this.ajaxRequest.send(null); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.JsonLoader.prototype.onJSONLoaded = function () { - if (this.ajaxRequest.readyState == 4) { - if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { - this.json = JSON.parse(this.ajaxRequest.responseText); - - if(this.json.frames) - { - // sprite sheet - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); - - } - else if(this.json.bones) - { - // spine animation - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - PIXI.AnimCache[this.url] = skeletonData; - this.onLoaded(); - } - else - { - this.onLoaded(); - } - } - else - { - this.onError(); - } - } -}; - -/** - * Invoke when json file loaded - * - * @method onLoaded - * @private - */ -PIXI.JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * Invoke when error occured - * - * @method onError - * @private - */ -PIXI.JsonLoader.prototype.onError = function () { - this.dispatchEvent({ - type: "error", - content: this - }); -}; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The sprite sheet loader is used to load in JSON sprite sheet data - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format - * There is a free version so thats nice, although the paid version is great value for money. - * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * This loader will also load the image file that the Spritesheet points to as well as the data. - * When loaded this class will dispatch a "loaded" event - * - * @class SpriteSheetLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ - -PIXI.SpriteSheetLoader = function (url, crossorigin) { - /* - * i use texture packer to load the assets.. - * http://www.codeandweb.com/texturepacker - * make sure to set the format as "JSON" - */ - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = null; - - /** - * The frames of the sprite sheet - * - * @property frames - * @type Object - */ - this.frames = {}; -}; - -// constructor -PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; - -/** - * This will begin loading the JSON file - * - * @method load - */ -PIXI.SpriteSheetLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); - jsonLoader.addEventListener("loaded", function (event) { - scope.json = event.content.json; - scope.onJSONLoaded(); - }); - jsonLoader.load(); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); -}; -/** - * Invoke when all files are loaded (json and texture) - * - * @method onLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onLoaded = function () { - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") - * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * When loaded this class will dispatch a 'loaded' event - * - * @class ImageLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the image - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.ImageLoader = function(url, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = PIXI.Texture.fromImage(url, crossorigin); - - /** - * if the image is loaded with loadFramedSpriteSheet - * frames will contain the sprite sheet frames - * - */ - this.frames = []; -}; - -// constructor -PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; - -/** - * Loads image or takes it from cache - * - * @method load - */ -PIXI.ImageLoader.prototype.load = function() -{ - if(!this.texture.baseTexture.hasLoaded) - { - var scope = this; - this.texture.baseTexture.addEventListener("loaded", function() - { - scope.onLoaded(); - }); - } - else - { - this.onLoaded(); - } -}; - -/** - * Invoked when image file is loaded or it is already cached and ready to use - * - * @method onLoaded - * @private - */ -PIXI.ImageLoader.prototype.onLoaded = function() -{ - this.dispatchEvent({type: "loaded", content: this}); -}; - -/** - * Loads image and split it to uniform sized frames - * - * - * @method loadFramedSpriteSheet - * @param frameWidth {Number} with of each frame - * @param frameHeight {Number} height of each frame - * @param textureName {String} if given, the frames will be cached in - format - */ -PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) -{ - this.frames = []; - var cols = Math.floor(this.texture.width / frameWidth); - var rows = Math.floor(this.texture.height / frameHeight); - - var i=0; - for (var y=0; y= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +} + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + + +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array)) + points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(typeof points[0] === 'number') { + var p = []; + for(var i = 0, il = points.length; i < il; i+=2) { + p.push( + new PIXI.Point(points[i], points[i + 1]) + ); + } + + points = p; + } + + this.points = points; +} + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = []; + for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +} + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; + +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayobjects + * + * @class Circle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +} + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +} + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + + +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayobjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +} + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + //and a radius of 0.5 + var normx = ((x - this.x) / this.width) - 0.5, + normy = ((y - this.y) / this.height) - 0.5; + + normx *= normx; + normy *= normy; + + return (normx + normy < 0.25); +} + +PIXI.Ellipse.getBounds = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +} + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; + + + +/* + * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV + * you both rock! + */ + +function determineMatrixArrayType() { + PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + return PIXI.Matrix; +} + +determineMatrixArrayType(); + +PIXI.mat3 = {}; + +PIXI.mat3.create = function() +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat3.identity = function(matrix) +{ + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat4 = {}; + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat3.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[3], a11 = mat[4], a12 = mat[5], + a20 = mat[6], a21 = mat[7], a22 = mat[8], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], + b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], + b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22; + + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; + dest[4] = b10 * a01 + b11 * a11 + b12 * a21; + dest[5] = b10 * a02 + b11 * a12 + b12 * a22; + + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; + dest[7] = b20 * a01 + b21 * a11 + b22 * a21; + dest[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return dest; +} + +PIXI.mat3.clone = function(mat) +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = mat[0]; + matrix[1] = mat[1]; + matrix[2] = mat[2]; + matrix[3] = mat[3]; + matrix[4] = mat[4]; + matrix[5] = mat[5]; + matrix[6] = mat[6]; + matrix[7] = mat[7]; + matrix[8] = mat[8]; + + return matrix; +} + +PIXI.mat3.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +} + +PIXI.mat3.toMat4 = function (mat, dest) +{ + if (!dest) { dest = PIXI.mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +} + + +///// + + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat4.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) + { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +} + +PIXI.mat4.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; + var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; + var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + // Cache only the current line of the second matrix + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[4]; + b1 = mat2[5]; + b2 = mat2[6]; + b3 = mat2[7]; + dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[8]; + b1 = mat2[9]; + b2 = mat2[10]; + b3 = mat2[11]; + dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[12]; + b1 = mat2[13]; + b2 = mat2[14]; + b3 = mat2[15]; + dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + return dest; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The base class for all objects that are rendered on the screen. + * + * @class DisplayObject + * @constructor + */ +PIXI.DisplayObject = function() +{ + this.last = this; + this.first = this; + /** + * The coordinate of the object relative to the local coordinates of the parent. + * + * @property position + * @type Point + */ + this.position = new PIXI.Point(); + + /** + * The scale factor of the object. + * + * @property scale + * @type Point + */ + this.scale = new PIXI.Point(1,1);//{x:1, y:1}; + + /** + * The pivot point of the displayObject that it rotates around + * + * @property pivot + * @type Point + */ + this.pivot = new PIXI.Point(0,0); + + /** + * The rotation of the object in radians. + * + * @property rotation + * @type Number + */ + this.rotation = 0; + + /** + * The opacity of the object. + * + * @property alpha + * @type Number + */ + this.alpha = 1; + + /** + * The visibility of the object. + * + * @property visible + * @type Boolean + */ + this.visible = true; + + /** + * This is the defined area that will pick up mouse / touch events. It is null by default. + * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) + * + * @property hitArea + * @type Rectangle|Circle|Ellipse|Polygon + */ + this.hitArea = null; + + /** + * This is used to indicate if the displayObject should display a mouse hand cursor on rollover + * + * @property buttonMode + * @type Boolean + */ + this.buttonMode = false; + + /** + * Can this object be rendered + * + * @property renderable + * @type Boolean + */ + this.renderable = false; + + /** + * [read-only] The display object container that contains this display object. + * + * @property parent + * @type DisplayObjectContainer + * @readOnly + */ + this.parent = null; + + /** + * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. + * + * @property stage + * @type Stage + * @readOnly + */ + this.stage = null; + + /** + * [read-only] The multiplied alpha of the displayobject + * + * @property worldAlpha + * @type Number + * @readOnly + */ + this.worldAlpha = 1; + + /** + * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property + * + * @property _interactive + * @type Boolean + * @readOnly + * @private + */ + this._interactive = false; + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [read-only] Current transform of the object locally + * + * @property localTransform + * @type Mat3 + * @readOnly + * @private + */ + this.localTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [NYI] Unkown + * + * @property color + * @type Array<> + * @private + */ + this.color = []; + + /** + * [NYI] Holds whether or not this object is dynamic, for rendering optimization + * + * @property dynamic + * @type Boolean + * @private + */ + this.dynamic = true; + + // chach that puppy! + this._sr = 0; + this._cr = 1; + + + this.filterArea = new PIXI.Rectangle(0,0,1,1); + + /* + * MOUSE Callbacks + */ + + /** + * A callback that is used when the users clicks on the displayObject with their mouse + * @method click + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user clicks the mouse down over the sprite + * @method mousedown + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject + * for this callback to be fired the mouse must have been pressed down over the displayObject + * @method mouseup + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject + * for this callback to be fired, The touch must have started over the displayObject + * @method mouseupoutside + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse rolls over the displayObject + * @method mouseover + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse leaves the displayObject + * @method mouseout + * @param interactionData {InteractionData} + */ + + + /* + * TOUCH Callbacks + */ + + /** + * A callback that is used when the users taps on the sprite with their finger + * basically a touch version of click + * @method tap + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user touch's over the displayObject + * @method touchstart + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases a touch over the displayObject + * @method touchend + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the touch that was over the displayObject + * for this callback to be fired, The touch must have started over the sprite + * @method touchendoutside + * @param interactionData {InteractionData} + */ +} + +// constructor +PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; + +/** + * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default + * Instead of using this function you can now simply set the interactive property to true or false + * + * @method setInteractive + * @param interactive {Boolean} + * @deprecated Simply set the `interactive` property directly + */ +PIXI.DisplayObject.prototype.setInteractive = function(interactive) +{ + this.interactive = interactive; +} + +/** + * Indicates if the sprite will have touch and mouse interactivity. It is false by default + * + * @property interactive + * @type Boolean + * @default false + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { + get: function() { + return this._interactive; + }, + set: function(value) { + this._interactive = value; + + // TODO more to be done here.. + // need to sort out a re-crawl! + if(this.stage)this.stage.dirty = true; + } +}); + +/** + * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. + * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. + * To remove a mask, set this property to null. + * + * @property mask + * @type Graphics + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { + get: function() { + return this._mask; + }, + set: function(value) { + + + if(value) + { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. + * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. + * To remove filters simply set this property to 'null' + * @property filters + * @type Array An array of filters + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + if(value) + { + if(this._filters)this.removeFilter(this._filters); + this.addFilter(value); + + // now put all the passes in one place.. + var passes = []; + for (var i = 0; i < value.length; i++) + { + var filterPasses = value[i].passes; + for (var j = 0; j < filterPasses.length; j++) + { + passes.push(filterPasses[j]); + }; + }; + + value.start.filterPasses = passes; + } + else + { + if(this._filters)this.removeFilter(this._filters); + } + + this._filters = value; + + + + + } +}); + +/* + * Adds a filter to this displayObject + * + * @method addFilter + * @param mask {Graphics} the graphics object to use as a filter + * @private + */ +PIXI.DisplayObject.prototype.addFilter = function(data) +{ + //if(this.filter)return; + //this.filter = true; +// data[0].target = this; + + + // insert a filter block.. + // TODO Onject pool thease bad boys.. + var start = new PIXI.FilterBlock(); + var end = new PIXI.FilterBlock(); + + data.start = start; + data.end = end; + + start.data = data; + end.data = data; + + start.first = start.last = this; + end.first = end.last = this; + + start.open = true; + + start.target = this; + + /* + * insert start + */ + + var childFirst = start + var childLast = start + var nextObject; + var previousObject; + + previousObject = this.first._iPrev; + + if(previousObject) + { + nextObject = previousObject._iNext; + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + } + else + { + nextObject = this; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + + // now insert the end filter block.. + + /* + * insert end filter + */ + var childFirst = end + var childLast = end + var nextObject = null; + var previousObject = null; + + previousObject = this.last; + nextObject = previousObject._iNext; + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + var updateLast = this; + + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = end; + } + updateLast = updateLast.parent; + } + + this.first = start; + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.addFilterBlocks(start, end); + } + +} + +/* + * Removes the filter to this displayObject + * + * @method removeFilter + * @private + */ +PIXI.DisplayObject.prototype.removeFilter = function(data) +{ + //if(!this.filter)return; + //this.filter = false; + // console.log("YUOIO") + // modify the list.. + var startBlock = data.start; + + + var nextObject = startBlock._iNext; + var previousObject = startBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + if(previousObject)previousObject._iNext = nextObject; + + this.first = startBlock._iNext; + + // remove the end filter + var lastBlock = data.end; + + var nextObject = lastBlock._iNext; + var previousObject = lastBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + // this is always true too! + var tempLast = lastBlock._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == lastBlock) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); + } +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObject.prototype.updateTransform = function() +{ + // TODO OPTIMIZE THIS!! with dirty + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + var localTransform = this.localTransform; + var parentTransform = this.parent.worldTransform; + var worldTransform = this.worldTransform; + //console.log(localTransform) + localTransform[0] = this._cr * this.scale.x; + localTransform[1] = -this._sr * this.scale.y + localTransform[3] = this._sr * this.scale.x; + localTransform[4] = this._cr * this.scale.y; + + // TODO --> do we even need a local matrix??? + + var px = this.pivot.x; + var py = this.pivot.y; + + // Cache the matrix values (makes for huge speed increases!) + var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], + a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], + + b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], + b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; + + localTransform[2] = a02 + localTransform[5] = a12 + + worldTransform[0] = b00 * a00 + b01 * a10; + worldTransform[1] = b00 * a01 + b01 * a11; + worldTransform[2] = b00 * a02 + b01 * a12 + b02; + + worldTransform[3] = b10 * a00 + b11 * a10; + worldTransform[4] = b10 * a01 + b11 * a11; + worldTransform[5] = b10 * a02 + b11 * a12 + b12; + + // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! + // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); + this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; + +} + +PIXI.visibleCount = 0; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A DisplayObjectContainer represents a collection of display objects. + * It is the base class of all display objects that act as a container for other objects. + * + * @class DisplayObjectContainer + * @extends DisplayObject + * @constructor + */ +PIXI.DisplayObjectContainer = function() +{ + PIXI.DisplayObject.call( this ); + + /** + * [read-only] The of children of this container. + * + * @property children + * @type Array + * @readOnly + */ + this.children = []; +} + +// constructor +PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; + +/** + * Adds a child to the container. + * + * @method addChild + * @param child {DisplayObject} The DisplayObject to add to the container + */ +PIXI.DisplayObjectContainer.prototype.addChild = function(child) +{ + if(child.parent != undefined) + { + + //// COULD BE THIS??? + child.parent.removeChild(child); + // return; + } + + child.parent = this; + + this.children.push(child); + + // update the stage refference.. + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // LINKED LIST // + + // modify the list.. + var childFirst = child.first + var childLast = child.last; + var nextObject; + var previousObject; + + // this could be wrong if there is a filter?? + if(this._filters || this._mask) + { + previousObject = this.last._iPrev; + } + else + { + previousObject = this.last; + } + + nextObject = previousObject._iNext; + + // always true in this case + // need to make sure the parents last is updated too + var updateLast = this; + var prevLast = previousObject; + + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + +} + +/** + * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown + * + * @method addChildAt + * @param child {DisplayObject} The child to add + * @param index {Number} The index to place the child in + */ +PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) +{ + if(index >= 0 && index <= this.children.length) + { + if(child.parent != undefined) + { + child.parent.removeChild(child); + } + child.parent = this; + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + var nextObject; + var previousObject; + + if(index == this.children.length) + { + previousObject = this.last; + var updateLast = this; + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + } + else if(index == 0) + { + previousObject = this; + } + else + { + previousObject = this.children[index-1].last; + } + + nextObject = previousObject._iNext; + + // always true in this case + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + this.children.splice(index, 0, child); + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + + } + else + { + throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); + } +} + +/** + * [NYI] Swaps the depth of 2 displayObjects + * + * @method swapChildren + * @param child {DisplayObject} + * @param child2 {DisplayObject} + * @private + */ +PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) +{ + /* + * this funtion needs to be recoded.. + * can be done a lot faster.. + */ + return; + + // need to fix this function :/ + /* + // TODO I already know this?? + var index = this.children.indexOf( child ); + var index2 = this.children.indexOf( child2 ); + + if ( index !== -1 && index2 !== -1 ) + { + // cool + + /* + if(this.stage) + { + // this is to satisfy the webGL batching.. + // TODO sure there is a nicer way to achieve this! + this.stage.__removeChild(child); + this.stage.__removeChild(child2); + + this.stage.__addChild(child); + this.stage.__addChild(child2); + } + + // swap the positions.. + this.children[index] = child2; + this.children[index2] = child; + + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + }*/ +} + +/** + * Returns the Child at the specified index + * + * @method getChildAt + * @param index {Number} The index to get the child from + */ +PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) +{ + if(index >= 0 && index < this.children.length) + { + return this.children[index]; + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + } +} + +/** + * Removes a child from the container. + * + * @method removeChild + * @param child {DisplayObject} The DisplayObject to remove + */ +PIXI.DisplayObjectContainer.prototype.removeChild = function(child) +{ + var index = this.children.indexOf( child ); + if ( index !== -1 ) + { + // unlink // + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + + var nextObject = childLast._iNext; + var previousObject = childFirst._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + if(this.last == childLast) + { + var tempLast = childFirst._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == childLast.last) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + } + + childLast._iNext = null; + childFirst._iPrev = null; + + // update the stage reference.. + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = null; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // webGL trim + if(child.__renderGroup) + { + child.__renderGroup.removeDisplayObjectAndChildren(child); + } + + child.parent = undefined; + this.children.splice( index, 1 ); + } + else + { + throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); + } +} + +/* + * Updates the container's children's transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObjectContainer.prototype.updateTransform = function() +{ + if(!this.visible)return; + + PIXI.DisplayObject.prototype.updateTransform.call( this ); + + for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation + */ +PIXI.MovieClip = function(textures) +{ + PIXI.Sprite.call(this, textures[0]); + + /** + * The array of textures that make up the animation + * + * @property textures + * @type Array + */ + this.textures = textures; + + /** + * The speed that the MovieClip will play at. Higher is faster, lower is slower + * + * @property animationSpeed + * @type Number + * @default 1 + */ + this.animationSpeed = 1; + + /** + * Whether or not the movie clip repeats after playing. + * + * @property loop + * @type Boolean + * @default true + */ + this.loop = true; + + /** + * Function to call when a MovieClip finishes playing + * + * @property onComplete + * @type Function + */ + this.onComplete = null; + + /** + * [read-only] The index MovieClips current frame (this may not have to be a whole number) + * + * @property currentFrame + * @type Number + * @default 0 + * @readOnly + */ + this.currentFrame = 0; + + /** + * [read-only] Indicates if the MovieClip is currently playing + * + * @property playing + * @type Boolean + * @readOnly + */ + this.playing = false; +} + +// constructor +PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); +PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; + +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + +/** + * Stops the MovieClip + * + * @method stop + */ +PIXI.MovieClip.prototype.stop = function() +{ + this.playing = false; +} + +/** + * Plays the MovieClip + * + * @method play + */ +PIXI.MovieClip.prototype.play = function() +{ + this.playing = true; +} + +/** + * Stops the MovieClip and goes to a specific frame + * + * @method gotoAndStop + * @param frameNumber {Number} frame index to stop at + */ +PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) +{ + this.playing = false; + this.currentFrame = frameNumber; + var round = (this.currentFrame + 0.5) | 0; + this.setTexture(this.textures[round % this.textures.length]); +} + +/** + * Goes to a specific frame and begins playing the MovieClip + * + * @method gotoAndPlay + * @param frameNumber {Number} frame index to start at + */ +PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) +{ + this.currentFrame = frameNumber; + this.playing = true; +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.MovieClip.prototype.updateTransform = function() +{ + PIXI.Sprite.prototype.updateTransform.call(this); + + if(!this.playing)return; + + this.currentFrame += this.animationSpeed; + + var round = (this.currentFrame + 0.5) | 0; + + if(this.loop || round < this.textures.length) + { + this.setTexture(this.textures[round % this.textures.length]); + } + else if(round >= this.textures.length) + { + this.gotoAndStop(this.textures.length - 1); + if(this.onComplete) + { + this.onComplete(); + } + } +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + + +PIXI.FilterBlock = function() +{ + this.visible = true; + this.renderable = true; +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text to split a line you can use "\n" + * + * @class Text + * @extends Sprite + * @constructor + * @param text {String} The copy that you would like the text to display + * @param [style] {Object} The style parameters + * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text = function(text, style) +{ + this.canvas = document.createElement("canvas"); + this.context = this.canvas.getContext("2d"); + PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); + + this.setText(text); + this.setStyle(style); + + this.updateText(); + this.dirty = false; +}; + +// constructor +PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); +PIXI.Text.prototype.constructor = PIXI.Text; + +/** + * Set the style of the text + * + * @method setStyle + * @param [style] {Object} The style parameters + * @param [style.font="bold 20pt Arial"] {String} The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text.prototype.setStyle = function(style) +{ + style = style || {}; + style.font = style.font || "bold 20pt Arial"; + style.fill = style.fill || "black"; + style.align = style.align || "left"; + style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 + style.strokeThickness = style.strokeThickness || 0; + style.wordWrap = style.wordWrap || false; + style.wordWrapWidth = style.wordWrapWidth || 100; + this.style = style; + this.dirty = true; +}; + +/** + * Set the copy for the text object. To split a line you can use "\n" + * + * @methos setText + * @param {String} text The copy that you would like the text to display + */ +PIXI.Text.prototype.setText = function(text) +{ + this.text = text.toString() || " "; + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.Text.prototype.updateText = function() +{ + this.context.font = this.style.font; + + var outputText = this.text; + + // word wrap + // preserve original text + if(this.style.wordWrap)outputText = this.wordWrap(this.text); + + //split text into lines + var lines = outputText.split(/(?:\r\n|\r|\n)/); + + //calculate text width + var lineWidths = []; + var maxLineWidth = 0; + for (var i = 0; i < lines.length; i++) + { + var lineWidth = this.context.measureText(lines[i]).width; + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + this.canvas.width = maxLineWidth + this.style.strokeThickness; + + //calculate text height + var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; + this.canvas.height = lineHeight * lines.length; + + //set canvas text styles + this.context.fillStyle = this.style.fill; + this.context.font = this.style.font; + + this.context.strokeStyle = this.style.stroke; + this.context.lineWidth = this.style.strokeThickness; + + this.context.textBaseline = "top"; + + //draw lines line by line + for (i = 0; i < lines.length; i++) + { + var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); + + if(this.style.align == "right") + { + linePosition.x += maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + linePosition.x += (maxLineWidth - lineWidths[i]) / 2; + } + + if(this.style.stroke && this.style.strokeThickness) + { + this.context.strokeText(lines[i], linePosition.x, linePosition.y); + } + + if(this.style.fill) + { + this.context.fillText(lines[i], linePosition.x, linePosition.y); + } + } + + this.updateTexture(); +}; + +/** + * Updates texture size based on canvas size + * + * @method updateTexture + * @private + */ +PIXI.Text.prototype.updateTexture = function() +{ + this.texture.baseTexture.width = this.canvas.width; + this.texture.baseTexture.height = this.canvas.height; + this.texture.frame.width = this.canvas.width; + this.texture.frame.height = this.canvas.height; + + this._width = this.canvas.width; + this._height = this.canvas.height; + + PIXI.texturesToUpdate.push(this.texture.baseTexture); +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.Text.prototype.updateTransform = function() +{ + if(this.dirty) + { + this.updateText(); + this.dirty = false; + } + + PIXI.Sprite.prototype.updateTransform.call(this); +}; + +/* + * http://stackoverflow.com/users/34441/ellisbben + * great solution to the problem! + * + * @method determineFontHeight + * @param fontStyle {Object} + * @private + */ +PIXI.Text.prototype.determineFontHeight = function(fontStyle) +{ + // build a little reference dictionary so if the font style has been used return a + // cached version... + var result = PIXI.Text.heightCache[fontStyle]; + + if(!result) + { + var body = document.getElementsByTagName("body")[0]; + var dummy = document.createElement("div"); + var dummyText = document.createTextNode("M"); + dummy.appendChild(dummyText); + dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); + body.appendChild(dummy); + + result = dummy.offsetHeight; + PIXI.Text.heightCache[fontStyle] = result; + + body.removeChild(dummy); + } + + return result; +}; + +/** + * Applies newlines to a string to have it optimally fit into the horizontal + * bounds set by the Text object's wordWrapWidth property. + * + * @method wordWrap + * @param text {String} + * @private + */ +PIXI.Text.prototype.wordWrap = function(text) +{ + // Greedy wrapping algorithm that will wrap words as the line grows longer + // than its horizontal bounds. + var result = ""; + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) + { + var spaceLeft = this.style.wordWrapWidth; + var words = lines[i].split(" "); + for (var j = 0; j < words.length; j++) + { + var wordWidth = this.context.measureText(words[j]).width; + var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; + if(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 = this.style.wordWrapWidth - wordWidth; + } + else + { + spaceLeft -= wordWidthWithSpace; + result += words[j] + " "; + } + } + result += "\n"; + } + return result; +}; + +/** + * Destroys this text object + * + * @method destroy + * @param destroyTexture {Boolean} + */ +PIXI.Text.prototype.destroy = function(destroyTexture) +{ + if(destroyTexture) + { + this.texture.destroy(); + } + +}; + +PIXI.Text.heightCache = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" + * You can generate the fnt files using + * http://www.angelcode.com/products/bmfont/ for windows or + * http://www.bmglyph.com/ for mac. + * + * @class BitmapText + * @extends DisplayObjectContainer + * @constructor + * @param text {String} The copy that you would like the text to display + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText = function(text, style) +{ + PIXI.DisplayObjectContainer.call(this); + + this.setText(text); + this.setStyle(style); + this.updateText(); + this.dirty = false + +}; + +// constructor +PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; + +/** + * Set the copy for the text object + * + * @method setText + * @param text {String} The copy that you would like the text to display + */ +PIXI.BitmapText.prototype.setText = function(text) +{ + this.text = text || " "; + this.dirty = true; +}; + +/** + * Set the style of the text + * + * @method setStyle + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText.prototype.setStyle = function(style) +{ + style = style || {}; + style.align = style.align || "left"; + this.style = style; + + var font = style.font.split(" "); + this.fontName = font[font.length - 1]; + this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; + + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.BitmapText.prototype.updateText = function() +{ + var data = PIXI.BitmapText.fonts[this.fontName]; + var pos = new PIXI.Point(); + var prevCharCode = null; + var chars = []; + var maxLineWidth = 0; + var lineWidths = []; + var line = 0; + var scale = this.fontSize / data.size; + for(var i = 0; i < this.text.length; i++) + { + var charCode = this.text.charCodeAt(i); + if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) + { + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + line++; + + pos.x = 0; + pos.y += data.lineHeight; + prevCharCode = null; + continue; + } + + var charData = data.chars[charCode]; + if(!charData) continue; + + if(prevCharCode && charData[prevCharCode]) + { + pos.x += charData.kerning[prevCharCode]; + } + chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); + pos.x += charData.xAdvance; + + prevCharCode = charCode; + } + + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + + var lineAlignOffsets = []; + for(i = 0; i <= line; i++) + { + var alignOffset = 0; + if(this.style.align == "right") + { + alignOffset = maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + alignOffset = (maxLineWidth - lineWidths[i]) / 2; + } + lineAlignOffsets.push(alignOffset); + } + + for(i = 0; i < chars.length; i++) + { + var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); + c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; + c.position.y = chars[i].position.y * scale; + c.scale.x = c.scale.y = scale; + this.addChild(c); + } + + this.width = pos.x * scale; + this.height = (pos.y + data.lineHeight) * scale; +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.BitmapText.prototype.updateTransform = function() +{ + if(this.dirty) + { + while(this.children.length > 0) + { + this.removeChild(this.getChildAt(0)); + } + this.updateText(); + + this.dirty = false; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + +PIXI.BitmapText.fonts = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + /** + * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive + * This manager also supports multitouch. + * + * @class InteractionManager + * @constructor + * @param stage {Stage} The stage to handle interactions + */ +PIXI.InteractionManager = function(stage) +{ + /** + * a refference to the stage + * + * @property stage + * @type Stage + */ + this.stage = stage; + + /** + * the mouse data + * + * @property mouse + * @type InteractionData + */ + this.mouse = new PIXI.InteractionData(); + + /** + * an object that stores current touches (InteractionData) by id reference + * + * @property touchs + * @type Object + */ + this.touchs = {}; + + + + // helpers + this.tempPoint = new PIXI.Point(); + //this.tempMatrix = mat3.create(); + + this.mouseoverEnabled = true; + + //tiny little interactiveData pool! + this.pool = []; + + this.interactiveItems = []; + this.interactionDOMElement = null; + + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + + this.last = 0; +} + +// constructor +PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; + +/** + * Collects an interactive sprite recursively to have their interactions managed + * + * @method collectInteractiveSprite + * @param displayObject {DisplayObject} the displayObject to collect + * @param iParent {DisplayObject} + * @private + */ +PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) +{ + var children = displayObject.children; + var length = children.length; + + /// make an interaction tree... {item.__interactiveParent} + for (var i = length-1; i >= 0; i--) + { + var child = children[i]; + +// if(child.visible) { + // push all interactive bits + if(child.interactive) + { + iParent.interactiveChildren = true; + //child.__iParent = iParent; + this.interactiveItems.push(child); + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, child); + } + } + else + { + child.__iParent = null; + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, iParent); + } + } +// } + } +} + +/** + * Sets the target for event delegation + * + * @method setTarget + * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to + * @private + */ +PIXI.InteractionManager.prototype.setTarget = function(target) +{ + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + + if (window.navigator.msPointerEnabled) + { + // time to remove some of that zoom in ja.. + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; + + // DO some window specific touch! + } + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); +} + + +/** + * updates the state of interactive objects + * + * @method update + * @private + */ +PIXI.InteractionManager.prototype.update = function() +{ + if(!this.target)return; + + // frequency of 30fps?? + var now = Date.now(); + var diff = now - this.last; + diff = (diff * 30) / 1000; + if(diff < 1)return; + this.last = now; + // + + // ok.. so mouse events?? + // yes for now :) + // OPTIMSE - how often to check?? + if(this.dirty) + { + this.dirty = false; + + var len = this.interactiveItems.length; + + for (var i=0; i < len; i++) { + this.interactiveItems[i].interactiveChildren = false; + } + + this.interactiveItems = []; + + if(this.stage.interactive)this.interactiveItems.push(this.stage); + // go through and collect all the objects that are interactive.. + this.collectInteractiveSprite(this.stage, this.stage); + } + + // loop through interactive objects! + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + + //if(!item.visible)continue; + + // OPTIMISATION - only calculate every time if the mousemove function exists.. + // OK so.. does the object have any other interactive functions? + // hit-test the clip! + + + if(item.mouseover || item.mouseout || item.buttonMode) + { + // ok so there are some functions so lets hit test it.. + item.__hit = this.hitTest(item, this.mouse); + this.mouse.target = item; + // ok so deal with interactions.. + // loks like there was a hit! + if(item.__hit) + { + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; + + if(!item.__isOver) + { + + if(item.mouseover)item.mouseover(this.mouse); + item.__isOver = true; + } + } + else + { + if(item.__isOver) + { + // roll out! + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } + } + + // ---> + } +} + +/** + * Is called when the mouse moves accross the renderer element + * + * @method onMouseMove + * @param event {Event} The DOM event of the mouse moving + * @private + */ +PIXI.InteractionManager.prototype.onMouseMove = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + // TODO optimize by not check EVERY TIME! maybe half as often? // + var rect = this.interactionDOMElement.getBoundingClientRect(); + + this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); + this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); + + var length = this.interactiveItems.length; + var global = this.mouse.global; + + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousemove) + { + //call the function! + item.mousemove(this.mouse); + } + } +} + +/** + * Is called when the mouse button is pressed down on the renderer element + * + * @method onMouseDown + * @param event {Event} The DOM event of a mouse button being pressed down + * @private + */ +PIXI.InteractionManager.prototype.onMouseDown = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + // loop through inteaction tree... + // hit test each item! -> + // get interactive items under point?? + //stage.__i + var length = this.interactiveItems.length; + var global = this.mouse.global; + + var index = 0; + var parent = this.stage; + + // while + // hit test + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousedown || item.click) + { + item.__mouseIsDown = true; + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit) + { + //call the function! + if(item.mousedown)item.mousedown(this.mouse); + item.__isDown = true; + + // just the one! + if(!item.interactiveChildren)break; + } + } + } +} + + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + +/** + * Is called when the mouse button is released on the renderer element + * + * @method onMouseUp + * @param event {Event} The DOM event of a mouse button being released + * @private + */ +PIXI.InteractionManager.prototype.onMouseUp = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + var global = this.mouse.global; + + + var length = this.interactiveItems.length; + var up = false; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mouseup || item.mouseupoutside || item.click) + { + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit && !up) + { + //call the function! + if(item.mouseup) + { + item.mouseup(this.mouse); + } + if(item.__isDown) + { + if(item.click)item.click(this.mouse); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.mouseupoutside)item.mouseupoutside(this.mouse); + } + } + + item.__isDown = false; + } + } +} + +/** + * Tests if the current mouse coords hit a sprite + * + * @method hitTest + * @param item {DisplayObject} The displayObject to test for a hit + * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit + * @private + */ +PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) +{ + var global = interactionData.global; + + if(item.vcount !== PIXI.visibleCount)return false; + + var isSprite = (item instanceof PIXI.Sprite), + worldTransform = item.worldTransform, + a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10), + x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; + + interactionData.target = item; + + //a sprite or display object with a hit area defined + if(item.hitArea && item.hitArea.contains) { + if(item.hitArea.contains(x, y)) { + //if(isSprite) + interactionData.target = item; + + return true; + } + + return false; + } + // a sprite with no hitarea defined + else if(isSprite) + { + var width = item.texture.frame.width, + height = item.texture.frame.height, + x1 = -width * item.anchor.x, + y1; + + if(x > x1 && x < x1 + width) + { + y1 = -height * item.anchor.y; + + if(y > y1 && y < y1 + height) + { + // set the target property if a hit is true! + interactionData.target = item + return true; + } + } + } + + var length = item.children.length; + + for (var i = 0; i < length; i++) + { + var tempItem = item.children[i]; + var hit = this.hitTest(tempItem, interactionData); + if(hit) + { + // hmm.. TODO SET CORRECT TARGET? + interactionData.target = item + return true; + } + } + + return false; +} + +/** + * Is called when a touch is moved accross the renderer element + * + * @method onTouchMove + * @param event {Event} The DOM event of a touch moving accross the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchMove = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; + + // update the touch position + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + } + + var length = this.interactiveItems.length; + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + if(item.touchmove)item.touchmove(touchData); + } +} + +/** + * Is called when a touch is started on the renderer element + * + * @method onTouchStart + * @param event {Event} The DOM event of a touch starting on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchStart = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + + var changedTouches = event.changedTouches; + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + + var touchData = this.pool.pop(); + if(!touchData)touchData = new PIXI.InteractionData(); + + touchData.originalEvent = event || window.event; + + this.touchs[touchEvent.identifier] = touchData; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + + if(item.touchstart || item.tap) + { + item.__hit = this.hitTest(item, touchData); + + if(item.__hit) + { + //call the function! + if(item.touchstart)item.touchstart(touchData); + item.__isDown = true; + item.__touchData = touchData; + + if(!item.interactiveChildren)break; + } + } + } + } +} + +/** + * Is called when a touch is ended on the renderer element + * + * @method onTouchEnd + * @param event {Event} The DOM event of a touch ending on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchEnd = function(event) +{ + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + var up = false; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + var itemTouchData = item.__touchData; // <-- Here! + item.__hit = this.hitTest(item, touchData); + + if(itemTouchData == touchData) + { + // so this one WAS down... + touchData.originalEvent = event || window.event; + // hitTest?? + + if(item.touchend || item.tap) + { + if(item.__hit && !up) + { + if(item.touchend)item.touchend(touchData); + if(item.__isDown) + { + if(item.tap)item.tap(touchData); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.touchendoutside)item.touchendoutside(touchData); + } + } + + item.__isDown = false; + } + + item.__touchData = null; + + } + else + { + + } + } + // remove the touch.. + this.pool.push(touchData); + this.touchs[touchEvent.identifier] = null; + } +} + +/** + * Holds all information related to an Interaction event + * + * @class InteractionData + * @constructor + */ +PIXI.InteractionData = function() +{ + /** + * This point stores the global coords of where the touch/mouse event happened + * + * @property global + * @type Point + */ + this.global = new PIXI.Point(); + + // this is here for legacy... but will remove + this.local = new PIXI.Point(); + + /** + * The target Sprite that was interacted with + * + * @property target + * @type Sprite + */ + this.target; + + /** + * When passed to an event handler, this will be the original DOM Event that was captured + * + * @property originalEvent + * @type Event + */ + this.originalEvent; +} + +/** + * This will return the local coords of the specified displayObject for this InteractionData + * + * @method getLocalPosition + * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off + * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject + */ +PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) +{ + var worldTransform = displayObject.worldTransform; + var global = this.global; + + // do a cheeky transform to get the mouse coords; + var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10); + // set the mouse coords... + return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) +} + +// constructor +PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Stage represents the root of the display tree. Everything connected to the stage is rendered + * + * @class Stage + * @extends DisplayObjectContainer + * @constructor + * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format + * like: 0xFFFFFF for white + */ +PIXI.Stage = function(backgroundColor) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create(); + + /** + * Whether or not the stage is interactive + * + * @property interactive + * @type Boolean + */ + this.interactive = true; + + /** + * The interaction manage for this stage, manages all interactive activity on the stage + * + * @property interactive + * @type InteractionManager + */ + this.interactionManager = new PIXI.InteractionManager(this); + + /** + * Whether the stage is dirty and needs to have interactions updated + * + * @property dirty + * @type Boolean + * @private + */ + this.dirty = true; + + this.__childrenAdded = []; + this.__childrenRemoved = []; + + //the stage is it's own stage + this.stage = this; + + //optimize hit detection a bit + this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); + + this.setBackgroundColor(backgroundColor); + this.worldVisible = true; +} + +// constructor +PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Stage.prototype.constructor = PIXI.Stage; + +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Stage.prototype.updateTransform = function() +{ + this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; + + for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + +/** + * A polyfill for Function.prototype.bind + * + * @method bind + */ +if (typeof Function.prototype.bind != 'function') { + Function.prototype.bind = (function () { + var slice = Array.prototype.slice; + return function (thisArg) { + var target = this, boundArgs = slice.call(arguments, 1); + + if (typeof target != 'function') throw new TypeError(); + + function bound() { + var args = boundArgs.concat(slice.call(arguments)); + target.apply(this instanceof bound ? this : thisArg, args); + } + + bound.prototype = (function F(proto) { + proto && (F.prototype = proto); + if (!(this instanceof F)) return new F; + })(target.prototype); + + return bound; + }; + })(); +} + +/** + * A wrapper for ajax requests to be handled cross browser + * + * @class AjaxRequest + * @constructor + */ +var AjaxRequest = PIXI.AjaxRequest = function() +{ + var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE + + if (window.ActiveXObject) + { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) + for (var i=0; i>>>>>>>>") + console.log("_") + var safe = 0; + var tmp = item.first; + console.log(tmp); + + while(tmp._iNext) + { + safe++; + tmp = tmp._iNext; + console.log(tmp); + // console.log(tmp); + + if(safe > 100) + { + console.log("BREAK") + break + } + } +} + + + + + + +/** + * https://github.com/mrdoob/eventtarget.js/ + * THankS mr DOob! + */ + +/** + * Adds event emitter functionality to a class + * + * @class EventTarget + * @example + * function MyEmitter() { + * PIXI.EventTarget.call(this); //mixes in event target stuff + * } + * + * var em = new MyEmitter(); + * em.emit({ type: 'eventName', data: 'some data' }); + */ +PIXI.EventTarget = function () { + + var listeners = {}; + + this.addEventListener = this.on = function ( type, listener ) { + + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + } + + }; + + this.dispatchEvent = this.emit = function ( event ) { + + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + + } + + }; + + this.removeEventListener = this.off = function ( type, listener ) { + + var index = listeners[ type ].indexOf( listener ); + + if ( index !== - 1 ) { + + listeners[ type ].splice( index, 1 ); + + } + + }; + +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * This helper function will automatically detect which renderer you should be using. + * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by + * the browser then this function will return a canvas renderer + * + * @method autoDetectRenderer + * @static + * @param width {Number} the width of the renderers view + * @param height {Number} the height of the renderers view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias + */ +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) +{ + if(!width)width = 800; + if(!height)height = 600; + + // BORROWED from Mr Doob (mrdoob.com) + var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); + + if(webgl) + { + var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); + webgl = !ie; + } + + //console.log(webgl); + if( webgl ) + { + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); + } + + return new PIXI.CanvasRenderer(width, height, view, transparent); +}; + + + +/* + PolyK library + url: http://polyk.ivank.net + Released under MIT licence. + + Copyright (c) 2012 Ivan Kuckir + + 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. + + This is an amazing lib! + + slightly modified by mat groves (matgroves.com); +*/ + +PIXI.PolyK = {}; + +/** + * Triangulates shapes for webGL graphic fills + * + * @method Triangulate + * @namespace PolyK + * @constructor + */ +PIXI.PolyK.Triangulate = function(p) +{ + var sign = true; + + var n = p.length>>1; + if(n<3) return []; + var tgs = []; + var avl = []; + for(var i=0; i 3) + { + var i0 = avl[(i+0)%al]; + var i1 = avl[(i+1)%al]; + var i2 = avl[(i+2)%al]; + + var ax = p[2*i0], ay = p[2*i0+1]; + var bx = p[2*i1], by = p[2*i1+1]; + var cx = p[2*i2], cy = p[2*i2+1]; + + var earFound = false; + if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) + { + earFound = true; + for(var j=0; j 3*al) + { + // need to flip flip reverse it! + // reset! + if(sign) + { + var tgs = []; + avl = []; + for(var i=0; i= 0) && (v >= 0) && (u + v < 1); +} + +/** + * Checks if a shape is convex + * + * @class _convex + * @namespace PolyK + * @private + */ +PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) +{ + return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.initDefaultShaders = function() +{ + PIXI.primitiveShader = new PIXI.PrimitiveShader(); + PIXI.primitiveShader.init(); + + PIXI.stripShader = new PIXI.StripShader(); + PIXI.stripShader.init(); + + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + + var gl = PIXI.gl; + var shaderProgram = PIXI.defaultShader.program; + + + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.activatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.primitiveShader.program); + + gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + + gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); +} + +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + + gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + +} + +PIXI.activateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.stripShader.program); + // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.deactivateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +/* + +SHADER COMPILER HELPERS +*/ + +PIXI.CompileVertexShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); +} + +PIXI.CompileFragmentShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); +} + +PIXI._CompileShader = function(gl, shaderSrc, shaderType) +{ + var src = shaderSrc.join("\n"); + var shader = gl.createShader(shaderType); + gl.shaderSource(shader, src); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} + + +PIXI.compileProgram = function(vertexSrc, fragmentSrc) +{ + var gl = PIXI.gl; + var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); + var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); + + var shaderProgram = gl.createProgram(); + + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialise shaders"); + } + + return shaderProgram; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * @author Richard Davey http://www.photonstorm.com @photonstorm + */ + +/** +* @class PIXI.PixiShader +* @constructor +*/ +PIXI.PixiShader = function() +{ + /** + * @property {any} program - The WebGL program. + */ + this.program; + + /** + * @property {array} fragmentSrc - The fragment shader. + */ + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + + /** + * @property {number} textureCount - A local texture counter for multi-texture shaders. + */ + this.textureCount = 0; + +} + +/** +* @method PIXI.PixiShader#init +*/ +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +/** +* Updates the shader uniform values. +* Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/ +* http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf +* +* @method PIXI.PixiShader#syncUniforms +*/ +PIXI.PixiShader.prototype.syncUniforms = function() +{ + this.textureCount = 1; + + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + var type = this.uniforms[key].type; + var transpose = false; + + if (this.uniforms[key].transpose) + { + transpose = this.uniforms[key].transpose; + } + + if (type == "1f") + { + // void uniform1f(WebGLUniformLocation? location, GLfloat x); + gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1fv") + { + // void uniform1fv(WebGLUniformLocation? location, Float32Array v); + // void uniform1fv(WebGLUniformLocation? location, sequence v); + gl.uniform1fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1i") + { + // void uniform1i(WebGLUniformLocation? location, GLint x); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1iv") + { + // void uniform1iv(WebGLUniformLocation? location, Int32Array v); + // void uniform1iv(WebGLUniformLocation? location, sequence v); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2f") + { + // void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y); + gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2fv") + { + // void uniform2fv(WebGLUniformLocation? location, Float32Array v); + // void uniform2fv(WebGLUniformLocation? location, sequence v); + gl.uniform2fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2i") + { + // void uniform2i(WebGLUniformLocation? location, GLint x, GLint y); + gl.uniform2i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2iv") + { + // void uniform2iv(WebGLUniformLocation? location, Int32Array v); + // void uniform2iv(WebGLUniformLocation? location, sequence v); + gl.uniform2iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3f") + { + // void uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z); + gl.uniform3f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3fv") + { + // void uniform3fv(WebGLUniformLocation? location, Float32Array v); + // void uniform3fv(WebGLUniformLocation? location, sequence v); + gl.uniform3fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3i") + { + // void uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z); + gl.uniform3i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3iv") + { + // void uniform3iv(WebGLUniformLocation? location, Int32Array v); + // void uniform3iv(WebGLUniformLocation? location, sequence v); + gl.uniform3iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4f") + { + // void uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + gl.uniform4f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4fv") + { + // void uniform4fv(WebGLUniformLocation? location, Float32Array v); + // void uniform4fv(WebGLUniformLocation? location, sequence v); + gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4i") + { + // void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w); + gl.uniform4i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4iv") + { + // void uniform4iv(WebGLUniformLocation? location, Int32Array v); + // void uniform4iv(WebGLUniformLocation? location, sequence v); + gl.uniform4iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "mat2") + { + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix2fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat3") + { + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix3fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat4") + { + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "sampler2D") + { + if (this.uniforms[key].value.baseTexture.hasLoaded) + { + var texture = this.uniforms[key].value.baseTexture._glTexture; + var image = this.uniforms[key].value.baseTexture.source; + var format = gl.RGBA; + + if (this.uniforms[key].format && this.uniforms[key].format == 'luminance') + { + format = gl.LUMINANCE; + } + + gl.activeTexture(gl['TEXTURE' + this.textureCount]); + + if (this.uniforms[key].wrap) + { + if (this.uniforms[key].wrap == 'no-repeat' || this.uniforms[key].wrap === false) + { + this.createGLTextureLinear(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'repeat' || this.uniforms[key].wrap === true) + { + this.createGLTexture(gl, image, format, texture); + } + else if (this.uniforms[key].wrap == 'nearest-repeat') + { + this.createGLTextureNearestRepeat(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'nearest') + { + this.createGLTextureNearest(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'audio') + { + this.createAudioTexture(gl, texture); + } + else if (this.uniforms[key].wrap == 'keyboard') + { + this.createKeyboardTexture(gl, texture); + } + } + else + { + this.createGLTextureLinear(gl, image, texture); + } + + gl.uniform1i(this.uniforms[key].uniformLocation, this.textureCount); + + this.textureCount++; + } + } + } + +}; + +/** +* Binds the given texture and image data. The texture is set to REPEAT. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTexture +*/ +PIXI.PixiShader.prototype.createGLTexture = function(gl, image, format, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.generateMipmap(gl.TEXTURE_2D); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureLinear +*/ +PIXI.PixiShader.prototype.createGLTextureLinear = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture and image data. The texture is set to REPEAT with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearestRepeat +*/ +PIXI.PixiShader.prototype.createGLTextureNearestRepeat = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearest +*/ +PIXI.PixiShader.prototype.createGLTextureNearest = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with real-time audio data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createAudioTexture +*/ +PIXI.PixiShader.prototype.createAudioTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 512, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with keyboard input data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createKeyboardTexture +*/ +PIXI.PixiShader.prototype.createKeyboardTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 256, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +PIXI.PixiShader.defaultVertexSrc = [ + + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "varying vec2 vTextureCoord;", + + "varying float vColor;", + + "const vec2 center = vec2(-1.0, 1.0);", + + "void main(void) {", + "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" +]; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.StripShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float alpha;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", + "gl_FragColor = gl_FragColor * alpha;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "varying vec2 vTextureCoord;", + "varying vec2 offsetVector;", + "varying float vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" + ]; +} + +PIXI.StripShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PrimitiveShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec4 vColor;", + "void main(void) {", + "gl_FragColor = vColor;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec4 aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "uniform float alpha;", + "varying vec4 vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vColor = aColor * alpha;", + "}" + ]; + +} + +PIXI.PrimitiveShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A set of functions used by the webGL renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.WebGLGraphics = function() +{ + +} + +/** + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param projection {Object} + */ +PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) +{ + var gl = PIXI.gl; + + if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, + buffer:gl.createBuffer(), + indexBuffer:gl.createBuffer()}; + + if(graphics.dirty) + { + graphics.dirty = false; + + if(graphics.clearDirty) + { + graphics.clearDirty = false; + + graphics._webGL.lastIndex = 0; + graphics._webGL.points = []; + graphics._webGL.indices = []; + + } + + PIXI.WebGLGraphics.updateGraphics(graphics); + } + + PIXI.activatePrimitiveShader(); + + // This could be speeded up fo sure! + var m = PIXI.mat3.clone(graphics.worldTransform); + + PIXI.mat3.transpose(m); + + // set the matrix transform for the + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); + + gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); + gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + + gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); + gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); + + // set the index buffer! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + + + gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + + PIXI.deactivatePrimitiveShader(); + + + // return to default shader... +// PIXI.activateShader(PIXI.defaultShader); +} + +/** + * Updates the graphics object + * + * @static + * @private + * @method updateGraphics + * @param graphics {Graphics} + */ +PIXI.WebGLGraphics.updateGraphics = function(graphics) +{ + for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + + if(data.type == PIXI.Graphics.POLY) + { + if(data.fill) + { + if(data.points.length>3) + PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); + } + + if(data.lineWidth > 0) + { + PIXI.WebGLGraphics.buildLine(data, graphics._webGL); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); + } + else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) + { + PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); + } + }; + + graphics._webGL.lastIndex = graphics.graphicsData.length; + + var gl = PIXI.gl; + + graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); + + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); + + graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); +} + +/** + * Builds a rectangle to draw + * + * @static + * @private + * @method buildRectangle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vertPos = verts.length/6; + + // start + verts.push(x, y); + verts.push(r, g, b, alpha); + + verts.push(x + width, y); + verts.push(r, g, b, alpha); + + verts.push(x , y + height); + verts.push(r, g, b, alpha); + + verts.push(x + width, y + height); + verts.push(r, g, b, alpha); + + // insert 2 dead triangles.. + indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) + } + + if(graphicsData.lineWidth) + { + graphicsData.points = [x, y, + x + width, y, + x + width, y + height, + x, y + height, + x, y]; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a circle to draw + * + * @static + * @private + * @method buildCircle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + var totalSegs = 40; + var seg = (Math.PI * 2) / totalSegs ; + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vecPos = verts.length/6; + + indices.push(vecPos); + + for (var i=0; i < totalSegs + 1 ; i++) + { + verts.push(x,y, r, g, b, alpha); + + verts.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height, + r, g, b, alpha); + + indices.push(vecPos++, vecPos++); + }; + + indices.push(vecPos-1); + } + + if(graphicsData.lineWidth) + { + graphicsData.points = []; + + for (var i=0; i < totalSegs + 1; i++) + { + graphicsData.points.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height) + }; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a line to draw + * + * @static + * @private + * @method buildLine + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) +{ + // TODO OPTIMISE! + + var wrap = true; + var points = graphicsData.points; + if(points.length == 0)return; + + // if the line width is an odd number add 0.5 to align to a whole pixel + if(graphicsData.lineWidth%2) + { + for (var i = 0; i < points.length; i++) { + points[i] += 0.5; + }; + } + + // get first and last point.. figure out the middle! + var firstPoint = new PIXI.Point( points[0], points[1] ); + var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + // if the first point is the last point - goona have issues :) + if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) + { + points.pop(); + points.pop(); + + lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; + var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; + + points.unshift(midPointX, midPointY); + points.push(midPointX, midPointY) + } + + var verts = webGLData.points; + var indices = webGLData.indices; + var length = points.length / 2; + var indexCount = points.length; + var indexStart = verts.length/6; + + // DRAW the Line + var width = graphicsData.lineWidth / 2; + + // sort color + var color = HEXtoRGB(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var p1x, p1y, p2x, p2y, p3x, p3y; + var perpx, perpy, perp2x, perp2y, perp3x, perp3y; + var ipx, ipy; + var a1, b1, c1, a2, b2, c2; + var denom, pdist, dist; + + p1x = points[0]; + p1y = points[1]; + + p2x = points[2]; + p2y = points[3]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + // start + verts.push(p1x - perpx , p1y - perpy, + r, g, b, alpha); + + verts.push(p1x + perpx , p1y + perpy, + r, g, b, alpha); + + for (var i = 1; i < length-1; i++) + { + p1x = points[(i-1)*2]; + p1y = points[(i-1)*2 + 1]; + + p2x = points[(i)*2] + p2y = points[(i)*2 + 1] + + p3x = points[(i+1)*2]; + p3y = points[(i+1)*2 + 1]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + perp2x = -(p2y - p3y); + perp2y = p2x - p3x; + + dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); + perp2x /= dist; + perp2y /= dist; + perp2x *= width; + perp2y *= width; + + a1 = (-perpy + p1y) - (-perpy + p2y); + b1 = (-perpx + p2x) - (-perpx + p1x); + c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); + a2 = (-perp2y + p3y) - (-perp2y + p2y); + b2 = (-perp2x + p2x) - (-perp2x + p3x); + c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); + + denom = a1*b2 - a2*b1; + + if(Math.abs(denom) < 0.1 ) + { + + denom+=10.1; + verts.push(p2x - perpx , p2y - perpy, + r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy, + r, g, b, alpha); + + continue; + } + + px = (b1*c2 - b2*c1)/denom; + py = (a2*c1 - a1*c2)/denom; + + + pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); + + + if(pdist > 140 * 140) + { + perp3x = perpx - perp2x; + perp3y = perpy - perp2y; + + dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); + perp3x /= dist; + perp3y /= dist; + perp3x *= width; + perp3y *= width; + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x + perp3x, p2y +perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + indexCount++; + } + else + { + + verts.push(px , py); + verts.push(r, g, b, alpha); + + verts.push(p2x - (px-p2x), p2y - (py - p2y)); + verts.push(r, g, b, alpha); + } + } + + p1x = points[(length-2)*2] + p1y = points[(length-2)*2 + 1] + + p2x = points[(length-1)*2] + p2y = points[(length-1)*2 + 1] + + perpx = -(p1y - p2y) + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + verts.push(p2x - perpx , p2y - perpy) + verts.push(r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy) + verts.push(r, g, b, alpha); + + indices.push(indexStart); + + for (var i=0; i < indexCount; i++) + { + indices.push(indexStart++); + }; + + indices.push(indexStart-1); +} + +/** + * Builds a polygon to draw + * + * @static + * @private + * @method buildPoly + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) +{ + var points = graphicsData.points; + if(points.length < 6)return; + + // get first and last point.. figure out the middle! + var verts = webGLData.points; + var indices = webGLData.indices; + + var length = points.length / 2; + + // sort color + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var triangles = PIXI.PolyK.Triangulate(points); + + var vertPos = verts.length / 6; + + for (var i=0; i < triangles.length; i+=3) + { + indices.push(triangles[i] + vertPos); + indices.push(triangles[i] + vertPos); + indices.push(triangles[i+1] + vertPos); + indices.push(triangles[i+2] +vertPos); + indices.push(triangles[i+2] + vertPos); + }; + + for (var i = 0; i < length; i++) + { + verts.push(points[i * 2], points[i * 2 + 1], + r, g, b, alpha); + }; +} + +function HEXtoRGB(hex) { + return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); + +// an instance of the gl context.. +// only one at the moment :/ +PIXI.gl; + +/** + * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer + * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. + * So no need for Sprite Batch's or Sprite Cloud's + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class WebGLRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) + * + */ +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) +{ + // do a catch.. only 1 webGL renderer.. + + this.transparent = !!transparent; + + this.width = width || 800; + this.height = height || 600; + + this.view = view || document.createElement( 'canvas' ); + this.view.width = this.width; + this.view.height = this.height; + + // deal with losing context.. + var scope = this; + this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) + this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) + + this.batchs = []; + + var options = { + alpha: this.transparent, + antialias:!!antialias, // SPEED UP?? + premultipliedAlpha:false, + stencil:true + } + + //try 'experimental-webgl' + try { + PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); + } catch (e) { + //try 'webgl' + try { + PIXI.gl = this.gl = this.view.getContext("webgl", options); + } catch (e) { + // fail, not able to get a context + throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); + } + } + + PIXI.initDefaultShaders(); + + + + + // PIXI.activateDefaultShader(); + + var gl = this.gl; + + gl.useProgram(PIXI.defaultShader.program); + + + PIXI.WebGLRenderer.gl = gl; + + this.batch = new PIXI.WebGLBatch(gl); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, this.transparent); + + PIXI.projection = new PIXI.Point(400, 300); + PIXI.offset = new PIXI.Point(0, 0); + + // TODO remove thease globals.. + + this.resize(this.width, this.height); + this.contextLost = false; + + //PIXI.pushShader(PIXI.defaultShader); + + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); + // this.stageRenderGroup. = this.transparent +} + +// constructor +PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; + +/** + * Gets a new WebGLBatch from the pool + * + * @static + * @method getBatch + * @return {WebGLBatch} + * @private + */ +PIXI.WebGLRenderer.getBatch = function() +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * Puts a batch back into the pool + * + * @static + * @method returnBatch + * @param batch {WebGLBatch} The batch to return + * @private + */ +PIXI.WebGLRenderer.returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * Renders the stage to its webGL view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.WebGLRenderer.prototype.render = function(stage) +{ + if(this.contextLost)return; + + + // if rendering a new stage clear the batchs.. + if(this.__stage !== stage) + { + // TODO make this work + // dont think this is needed any more? + this.__stage = stage; + this.stageRenderGroup.setRenderable(stage); + } + + // update any textures + PIXI.WebGLRenderer.updateTextures(); + + // update the scene graph + PIXI.visibleCount++; + stage.updateTransform(); + + var gl = this.gl; + + // -- Does this need to be set every frame? -- // + gl.colorMask(true, true, true, this.transparent); + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + gl.clear(gl.COLOR_BUFFER_BIT); + + // HACK TO TEST + + this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + this.stageRenderGroup.render(PIXI.projection); + + // interaction + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // after rendering lets confirm all frames that have been uodated.. + if(PIXI.Texture.frameUpdates.length > 0) + { + for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) + { + PIXI.Texture.frameUpdates[i].updateFrame = false; + }; + + PIXI.Texture.frameUpdates = []; + } +} + +/** + * Updates the textures loaded into this webgl renderer + * + * @static + * @method updateTextures + * @private + */ +PIXI.WebGLRenderer.updateTextures = function() +{ + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; +} + +/** + * Updates a loaded webgl texture + * + * @static + * @method updateTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.updateTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(!texture._glTexture) + { + texture._glTexture = gl.createTexture(); + } + + if(texture.hasLoaded) + { + gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + + // reguler... + + if(!texture._powerOf2) + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + } +} + +/** + * Destroys a loaded webgl texture + * + * @method destroyTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.destroyTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(texture._glTexture) + { + texture._glTexture = gl.createTexture(); + gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + } +} + +/** + * resizes the webGL view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the webGL view + * @param height {Number} the new height of the webGL view + */ +PIXI.WebGLRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; + + this.gl.viewport(0, 0, this.width, this.height); + + //var projectionMatrix = this.projectionMatrix; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + //PIXI.size.x = this.width/2; + //PIXI.size.y = -this.height/2; + +// projectionMatrix[0] = 2/this.width; +// projectionMatrix[5] = -2/this.height; +// projectionMatrix[12] = -1; +// projectionMatrix[13] = 1; +} + +/** + * Handles a lost webgl context + * + * @method handleContextLost + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextLost = function(event) +{ + event.preventDefault(); + this.contextLost = true; +} + +/** + * Handles a restored webgl context + * + * @method handleContextRestored + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) +{ + this.gl = this.view.getContext("experimental-webgl", { + alpha: true + }); + + this.initShaders(); + + for(var key in PIXI.TextureCache) + { + var texture = PIXI.TextureCache[key].baseTexture; + texture._glTexture = null; + PIXI.WebGLRenderer.updateTexture(texture); + }; + + for (var i=0; i < this.batchs.length; i++) + { + this.batchs[i].restoreLostContext(this.gl)// + this.batchs[i].dirty = true; + }; + + PIXI._restoreBatchs(this.gl); + + this.contextLost = false; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._batchs = []; + +/** + * @private + */ +PIXI._getBatch = function(gl) +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * @private + */ +PIXI._returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * @private + */ +PIXI._restoreBatchs = function(gl) +{ + for (var i=0; i < PIXI._batchs.length; i++) + { + PIXI._batchs[i].restoreLostContext(gl); + }; +} + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. + * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites + * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled + * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @constructor + * @param gl {WebGLContext} an instance of the webGL context + */ +PIXI.WebGLBatch = function(gl) +{ + this.gl = gl; + + this.size = 0; + + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); + this.blendMode = PIXI.blendModes.NORMAL; + this.dynamicSize = 1; +} + +// constructor +PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; + +/** + * Cleans the batch so that is can be returned to an object pool and reused + * + * @method clean + */ +PIXI.WebGLBatch.prototype.clean = function() +{ + this.verticies = []; + this.uvs = []; + this.indices = []; + this.colors = []; + this.dynamicSize = 1; + this.texture = null; + this.last = null; + this.size = 0; + this.head; + this.tail; +} + +/** + * Recreates the buffers in the event of a context loss + * + * @method restoreLostContext + * @param gl {WebGLContext} + */ +PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) +{ + this.gl = gl; + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); +} + +/** + * inits the batch's texture and blend mode based if the supplied sprite + * + * @method init + * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with + * the same base texture and blend mode will be allowed to be added to this batch + */ +PIXI.WebGLBatch.prototype.init = function(sprite) +{ + sprite.batch = this; + this.dirty = true; + this.blendMode = sprite.blendMode; + this.texture = sprite.texture.baseTexture; + this.head = sprite; + this.tail = sprite; + this.size = 1; + + this.growBatch(); +} + +/** + * inserts a sprite before the specified sprite + * + * @method insertBefore + * @param sprite {Sprite} the sprite to be added + * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite + */ +PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + var tempPrev = nextSprite.__prev; + nextSprite.__prev = sprite; + sprite.__next = nextSprite; + + if(tempPrev) + { + sprite.__prev = tempPrev; + tempPrev.__next = sprite; + } + else + { + this.head = sprite; + } +} + +/** + * inserts a sprite after the specified sprite + * + * @method insertAfter + * @param sprite {Sprite} the sprite to be added + * @param previousSprite {Sprite} the first sprite will be inserted after this sprite + */ +PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + + var tempNext = previousSprite.__next; + previousSprite.__next = sprite; + sprite.__prev = previousSprite; + + if(tempNext) + { + sprite.__next = tempNext; + tempNext.__prev = sprite; + } + else + { + this.tail = sprite + } +} + +/** + * removes a sprite from the batch + * + * @method remove + * @param sprite {Sprite} the sprite to be removed + */ +PIXI.WebGLBatch.prototype.remove = function(sprite) +{ + this.size--; + + if(this.size == 0) + { + sprite.batch = null; + sprite.__prev = null; + sprite.__next = null; + return; + } + + if(sprite.__prev) + { + sprite.__prev.__next = sprite.__next; + } + else + { + this.head = sprite.__next; + this.head.__prev = null; + } + + if(sprite.__next) + { + sprite.__next.__prev = sprite.__prev; + } + else + { + this.tail = sprite.__prev; + this.tail.__next = null + } + + sprite.batch = null; + sprite.__next = null; + sprite.__prev = null; + this.dirty = true; +} + +/** + * Splits the batch into two with the specified sprite being the start of the new batch. + * + * @method split + * @param sprite {Sprite} the sprite that indicates where the batch should be split + * @return {WebGLBatch} the new batch + */ +PIXI.WebGLBatch.prototype.split = function(sprite) +{ + this.dirty = true; + + var batch = new PIXI.WebGLBatch(this.gl); + batch.init(sprite); + batch.texture = this.texture; + batch.tail = this.tail; + + this.tail = sprite.__prev; + this.tail.__next = null; + + sprite.__prev = null; + // return a splite batch! + + // TODO this size is wrong! + // need to recalculate :/ problem with a linked list! + // unless it gets calculated in the "clean"? + + // need to loop through items as there is no way to know the length on a linked list :/ + var tempSize = 0; + while(sprite) + { + tempSize++; + sprite.batch = batch; + sprite = sprite.__next; + } + + batch.size = tempSize; + this.size -= tempSize; + + return batch; +} + +/** + * Merges two batchs together + * + * @method merge + * @param batch {WebGLBatch} the batch that will be merged + */ +PIXI.WebGLBatch.prototype.merge = function(batch) +{ + this.dirty = true; + + this.tail.__next = batch.head; + batch.head.__prev = this.tail; + + this.size += batch.size; + + this.tail = batch.tail; + + var sprite = batch.head; + while(sprite) + { + sprite.batch = this; + sprite = sprite.__next; + } +} + +/** + * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this + * function is used to increase the size of the batch. It also creates a little extra room so + * that the batch does not need to be resized every time a sprite is added + * + * @method growBatch + */ +PIXI.WebGLBatch.prototype.growBatch = function() +{ + var gl = this.gl; + if( this.size == 1) + { + this.dynamicSize = 1; + } + else + { + this.dynamicSize = this.size * 1.5 + } + // grow verts + this.verticies = new Float32Array(this.dynamicSize * 8); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); + + this.uvs = new Float32Array( this.dynamicSize * 8 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); + + this.dirtyUVS = true; + + this.colors = new Float32Array( this.dynamicSize * 4 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); + + this.dirtyColors = true; + + this.indices = new Uint16Array(this.dynamicSize * 6); + var length = this.indices.length/6; + + for (var i=0; i < length; i++) + { + var index2 = i * 6; + var index3 = i * 4; + this.indices[index2 + 0] = index3 + 0; + this.indices[index2 + 1] = index3 + 1; + this.indices[index2 + 2] = index3 + 2; + this.indices[index2 + 3] = index3 + 0; + this.indices[index2 + 4] = index3 + 2; + this.indices[index2 + 5] = index3 + 3; + }; + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); +} + +/** + * Refresh's all the data in the batch and sync's it with the webGL buffers + * + * @method refresh + */ +PIXI.WebGLBatch.prototype.refresh = function() +{ + var gl = this.gl; + + if (this.dynamicSize < this.size) + { + this.growBatch(); + } + + var indexRun = 0; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; + var a, b, c, d, tx, ty; + + var displayObject = this.head; + + while(displayObject) + { + index = indexRun * 8; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + + colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + + displayObject = displayObject.__next; + + indexRun ++; + } + + this.dirtyUVS = true; + this.dirtyColors = true; +} + +/** + * Updates all the relevant geometry and uploads the data to the GPU + * + * @method update + */ +PIXI.WebGLBatch.prototype.update = function() +{ + var gl = this.gl; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 + + var a, b, c, d, tx, ty; + + var indexRun = 0; + + var displayObject = this.head; + var verticies = this.verticies; + var uvs = this.uvs; + var colors = this.colors; + + while(displayObject) + { + if(displayObject.vcount === PIXI.visibleCount) + { + width = displayObject.texture.frame.width; + height = displayObject.texture.frame.height; + + // TODO trim?? + aX = displayObject.anchor.x;// - displayObject.texture.trim.x + aY = displayObject.anchor.y; //- displayObject.texture.trim.y + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + index = indexRun * 8; + + worldTransform = displayObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + verticies[index + 0 ] = a * w1 + c * h1 + tx; + verticies[index + 1 ] = d * h1 + b * w1 + ty; + + verticies[index + 2 ] = a * w0 + c * h1 + tx; + verticies[index + 3 ] = d * h1 + b * w0 + ty; + + verticies[index + 4 ] = a * w0 + c * h0 + tx; + verticies[index + 5 ] = d * h0 + b * w0 + ty; + + verticies[index + 6] = a * w1 + c * h0 + tx; + verticies[index + 7] = d * h0 + b * w1 + ty; + + if(displayObject.updateFrame || displayObject.texture.updateFrame) + { + this.dirtyUVS = true; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + uvs[index + 0] = frame.x / tw; + uvs[index +1] = frame.y / th; + + uvs[index +2] = (frame.x + frame.width) / tw; + uvs[index +3] = frame.y / th; + + uvs[index +4] = (frame.x + frame.width) / tw; + uvs[index +5] = (frame.y + frame.height) / th; + + uvs[index +6] = frame.x / tw; + uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + } + + // TODO this probably could do with some optimisation.... + if(displayObject.cacheAlpha != displayObject.worldAlpha) + { + displayObject.cacheAlpha = displayObject.worldAlpha; + + var colorIndex = indexRun * 4; + colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; + this.dirtyColors = true; + } + } + else + { + index = indexRun * 8; + + verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; + } + + indexRun++; + displayObject = displayObject.__next; + } +} + +/** + * Draws the batch to the frame buffer + * + * @method render + */ +PIXI.WebGLBatch.prototype.render = function(start, end) +{ + start = start || 0; + + if(end == undefined)end = this.size; + + if(this.dirty) + { + this.refresh(); + this.dirty = false; + } + + if (this.size == 0)return; + + this.update(); + var gl = this.gl; + + //TODO optimize this! + + var shaderProgram = PIXI.defaultShader; + + //gl.useProgram(shaderProgram); + + // update the verts.. + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + // ok.. + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) + gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + // update the uvs + //var isDefault = (shaderProgram == PIXI.shaderProgram) + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + if(this.dirtyUVS) + { + this.dirtyUVS = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); + } + + gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); + + // update color! + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + + if(this.dirtyColors) + { + this.dirtyColors = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); + } + + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + var len = end - start; + + // DRAW THAT this! + gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be + * grouped into a batch. All the sprites in a batch can then be drawn in one go by the + * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch + * even if the batch only contains one sprite. Batching is handled automatically by the + * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @contructor + * @param gl {WebGLContext} An instance of the webGL context + */ +PIXI.WebGLRenderGroup = function(gl, transparent) +{ + this.gl = gl; + this.root; + + this.backgroundColor; + this.transparent = transparent == undefined ? true : transparent; + + this.batchs = []; + this.toRemove = []; + console.log(this.transparent) + this.filterManager = new PIXI.WebGLFilterManager(this.transparent); +} + +// constructor +PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; + +/** + * Add a display object to the webgl renderer + * + * @method setRenderable + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) +{ + // has this changed?? + if(this.root)this.removeDisplayObjectAndChildren(this.root); + + displayObject.worldVisible = displayObject.visible; + + // soooooo // + // to check if any batchs exist already?? + + // TODO what if its already has an object? should remove it + this.root = displayObject; + this.addDisplayObjectAndChildren(displayObject); +} + +/** + * Renders the stage to its webgl view + * + * @method render + * @param projection {Object} + */ +PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + + var gl = this.gl; + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + // will render all the elements in the group + var renderable; + + for (var i=0; i < this.batchs.length; i++) + { + + renderable = this.batchs[i]; + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + continue; + } + + // render special + this.renderSpecial(renderable, projection); + } + +} + +/** + * Renders a specific displayObject + * + * @method renderSpecific + * @param displayObject {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + var gl = this.gl; + + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + // to do! + // render part of the scene... + + var startIndex; + var startBatchIndex; + + var endIndex; + var endBatchIndex; + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.first; + while(nextRenderable._iNext) + { + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + nextRenderable = nextRenderable._iNext; + } + var startBatch = nextRenderable.batch; + //console.log(nextRenderable); + + //console.log(renderable) + if(nextRenderable instanceof PIXI.Sprite) + { + startBatch = nextRenderable.batch; + + var head = startBatch.head; + var next = head; + + // ok now we have the batch.. need to find the start index! + if(head == nextRenderable) + { + startIndex = 0; + } + else + { + startIndex = 1; + + while(head.__next != nextRenderable) + { + startIndex++; + head = head.__next; + } + } + } + else + { + startBatch = nextRenderable; + } + + // Get the LAST renderable object + var lastRenderable = displayObject.last; + while(lastRenderable._iPrev) + { + if(lastRenderable.renderable && lastRenderable.__renderGroup)break; + lastRenderable = lastRenderable._iNext; + } + + if(lastRenderable instanceof PIXI.Sprite) + { + endBatch = lastRenderable.batch; + + var head = endBatch.head; + + if(head == lastRenderable) + { + endIndex = 0; + } + else + { + endIndex = 1; + + while(head.__next != lastRenderable) + { + endIndex++; + head = head.__next; + } + } + } + else + { + endBatch = lastRenderable; + } + + //console.log(endBatch); + // TODO - need to fold this up a bit! + + if(startBatch == endBatch) + { + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex, endIndex+1); + } + else + { + this.renderSpecial(startBatch, projection); + } + return; + } + + // now we have first and last! + startBatchIndex = this.batchs.indexOf(startBatch); + endBatchIndex = this.batchs.indexOf(endBatch); + + // DO the first batch + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex); + } + else + { + this.renderSpecial(startBatch, projection); + } + + // DO the middle batchs.. + for (var i=startBatchIndex+1; i < endBatchIndex; i++) + { + renderable = this.batchs[i]; + + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + } + else + { + this.renderSpecial(renderable, projection); + } + } + + // DO the last batch.. + if(endBatch instanceof PIXI.WebGLBatch) + { + endBatch.render(0, endIndex+1); + } + else + { + this.renderSpecial(endBatch, projection); + } +} + +/** + * Renders a specific renderable + * + * @method renderSpecial + * @param renderable {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) +{ + + var worldVisible = renderable.vcount === PIXI.visibleCount + + + if(renderable instanceof PIXI.TilingSprite) + { + if(worldVisible)this.renderTilingSprite(renderable, projection); + } + else if(renderable instanceof PIXI.Strip) + { + if(worldVisible)this.renderStrip(renderable, projection); + } + else if(renderable instanceof PIXI.CustomRenderable) + { + if(worldVisible) renderable.renderWebGL(this, projection); + } + else if(renderable instanceof PIXI.Graphics) + { + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + } + else if(renderable instanceof PIXI.FilterBlock) + { + this.handleFilterBlock(renderable, projection); + } +} + +flip = false; +var maskStack = []; +var maskPosition = 0; + +//var usedMaskStack = []; + +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; + + if(filterBlock.open) + { + if(filterBlock.data instanceof Array) + { + this.filterManager.pushFilter(filterBlock); + // ok so.. + + } + else + { + maskPosition++; + + maskStack.push(filterBlock) + + gl.enable(gl.STENCIL_TEST); + + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); + + PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + } + } + else + { + if(filterBlock.data instanceof Array) + { + this.filterManager.popFilter(); + } + else + { + var maskData = maskStack.pop(filterBlock) + + + if(maskData) + { + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); + + PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + }; + + gl.disable(gl.STENCIL_TEST); + } + } +} + +/** + * Updates a webgl texture + * + * @method updateTexture + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) +{ + + // TODO definitely can optimse this function.. + + this.removeObject(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = displayObject.first; + while(previousRenderable != this.root) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + this.insertObject(displayObject, previousRenderable, nextRenderable); +} + +/** + * Adds filter blocks + * + * @method addFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) +{ + start.__renderGroup = this; + end.__renderGroup = this; + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = start; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + this.insertAfter(start, previousRenderable); + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var previousRenderable2 = end; + while(previousRenderable2 != this.root.first) + { + previousRenderable2 = previousRenderable2._iPrev; + if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; + } + this.insertAfter(end, previousRenderable2); +} + +/** + * Remove filter blocks + * + * @method removeFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) +{ + this.removeObject(start); + this.removeObject(end); +} + +/** + * Adds a display object and children to the webgl context + * + * @method addDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + + var previousRenderable = displayObject.first; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + // one the display object hits this. we can break the loop + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + do + { + tempObject.__renderGroup = this; + + if(tempObject.renderable) + { + + this.insertObject(tempObject, previousRenderable, nextRenderable); + previousRenderable = tempObject; + } + + tempObject = tempObject._iNext; + } + while(tempObject != testObject) +} + +/** + * Removes a display object and children to the webgl context + * + * @method removeDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup != this)return; + +// var displayObject = displayObject.first; + var lastObject = displayObject.last; + do + { + displayObject.__renderGroup = null; + if(displayObject.renderable)this.removeObject(displayObject); + displayObject = displayObject._iNext; + } + while(displayObject) +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertObject + * @param displayObject {DisplayObject} + * @param previousObject {DisplayObject} + * @param nextObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) +{ + // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED + var previousSprite = previousObject; + var nextSprite = nextObject; + + /* + * so now we have the next renderable and the previous renderable + * + */ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch + var nextBatch + + if(previousSprite instanceof PIXI.Sprite) + { + previousBatch = previousSprite.batch; + if(previousBatch) + { + if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) + { + previousBatch.insertAfter(displayObject, previousSprite); + return; + } + } + } + else + { + // TODO reword! + previousBatch = previousSprite; + } + + if(nextSprite) + { + if(nextSprite instanceof PIXI.Sprite) + { + nextBatch = nextSprite.batch; + + //batch may not exist if item was added to the display list but not to the webGL + if(nextBatch) + { + if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) + { + nextBatch.insertBefore(displayObject, nextSprite); + return; + } + else + { + if(nextBatch == previousBatch) + { + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(nextSprite); + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var batch = PIXI.WebGLRenderer.getBatch(); + + var index = this.batchs.indexOf( previousBatch ); + batch.init(displayObject); + this.batchs.splice(index+1, 0, batch, splitBatch); + + return; + } + } + } + } + else + { + // TODO re-word! + + nextBatch = nextSprite; + } + } + + /* + * looks like it does not belong to any batch! + * but is also not intersecting one.. + * time to create anew one! + */ + + var batch = PIXI.WebGLRenderer.getBatch(); + batch.init(displayObject); + + if(previousBatch) // if this is invalid it means + { + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, batch); + } + else + { + this.batchs.push(batch); + } + + return; + } + else if(displayObject instanceof PIXI.TilingSprite) + { + + // add to a batch!! + this.initTilingSprite(displayObject); + // this.batchs.push(displayObject); + + } + else if(displayObject instanceof PIXI.Strip) + { + // add to a batch!! + this.initStrip(displayObject); + // this.batchs.push(displayObject); + } + else if(displayObject)// instanceof PIXI.Graphics) + { + //displayObject.initWebGL(this); + + // add to a batch!! + //this.initStrip(displayObject); + //this.batchs.push(displayObject); + } + + this.insertAfter(displayObject, previousSprite); + + // insert and SPLIT! + +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertAfter + * @param item {DisplayObject} + * @param displayObject {DisplayObject} The object to insert + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) +{ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch = displayObject.batch; + + if(previousBatch) + { + // so this object is in a batch! + + // is it not? need to split the batch + if(previousBatch.tail == displayObject) + { + // is it tail? insert in to batchs + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item); + } + else + { + // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // + + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(displayObject.__next); + + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item, splitBatch); + } + } + else + { + this.batchs.push(item); + } + } + else + { + var index = this.batchs.indexOf( displayObject ); + this.batchs.splice(index+1, 0, item); + } +} + +/** + * Removes a displayObject from the linked list + * + * @method removeObject + * @param displayObject {DisplayObject} The object to remove + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) +{ + // loop through children.. + // display object // + + // add a child from the render group.. + // remove it and all its children! + //displayObject.cacheVisible = false;//displayObject.visible; + + /* + * removing is a lot quicker.. + * + */ + var batchToRemove; + + if(displayObject instanceof PIXI.Sprite) + { + // should always have a batch! + var batch = displayObject.batch; + if(!batch)return; // this means the display list has been altered befre rendering + + batch.remove(displayObject); + + if(batch.size==0) + { + batchToRemove = batch; + } + } + else + { + batchToRemove = displayObject; + } + + /* + * Looks like there is somthing that needs removing! + */ + if(batchToRemove) + { + var index = this.batchs.indexOf( batchToRemove ); + if(index == -1)return;// this means it was added then removed before rendered + + // ok so.. check to see if you adjacent batchs should be joined. + // TODO may optimise? + if(index == 0 || index == this.batchs.length-1) + { + // wha - eva! just get of the empty batch! + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + + return; + } + + if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) + { + if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) + { + //console.log("MERGE") + this.batchs[index-1].merge(this.batchs[index+1]); + + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); + this.batchs.splice(index, 2); + return; + } + } + + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + } +} + + +/** + * Initializes a tiling sprite + * + * @method initTilingSprite + * @param sprite {TilingSprite} The tiling sprite to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) +{ + var gl = this.gl; + + // make the texture tilable.. + + sprite.verticies = new Float32Array([0, 0, + sprite.width, 0, + sprite.width, sprite.height, + 0, sprite.height]); + + sprite.uvs = new Float32Array([0, 0, + 1, 0, + 1, 1, + 0, 1]); + + sprite.colors = new Float32Array([1,1,1,1]); + + sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); + + sprite._vertexBuffer = gl.createBuffer(); + sprite._indexBuffer = gl.createBuffer(); + sprite._uvBuffer = gl.createBuffer(); + sprite._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); + +// return ( (x > 0) && ((x & (x - 1)) == 0) ); + + if(sprite.texture.baseTexture._glTexture) + { + gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + sprite.texture.baseTexture._powerOf2 = true; + } + else + { + sprite.texture.baseTexture._powerOf2 = true; + } +} + +/** + * Renders a Strip + * + * @method renderStrip + * @param strip {Strip} The strip to render + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) +{ + var gl = this.gl; + + PIXI.activateStripShader(); + + var shader = PIXI.stripShader; + + var program = shader.program; + + var m = PIXI.mat3.clone(strip.worldTransform); + + PIXI.mat3.transpose(m); + +// console.log(projection) + // set the matrix transform for the + gl.uniformMatrix3fv(shader.translationMatrix, false, m); + gl.uniform2f(shader.projectionVector, projection.x, projection.y); + gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(shader.alpha, strip.worldAlpha); + + /* + if(strip.blendMode == PIXI.blendModes.NORMAL) + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); + } + */ + + //console.log("!!") + if(!strip.dirty) + { + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + } + else + { + strip.dirty = false; + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + // console.log(strip.texture.baseTexture._glTexture) + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); + + } + + gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); + + PIXI.deactivateStripShader(); + //gl.useProgram(PIXI.currentProgram); +} + +/** + * Renders a TilingSprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tiling sprite to render + * @param projectionMatrix {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) +{ + var gl = this.gl; + + + var shaderProgram = PIXI.shaderProgram; + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + var offsetX = tilePosition.x/sprite.texture.baseTexture.width; + var offsetY = tilePosition.y/sprite.texture.baseTexture.height; + + var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; + var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; + + sprite.uvs[0] = 0 - offsetX; + sprite.uvs[1] = 0 - offsetY; + + sprite.uvs[2] = (1 * scaleX) -offsetX; + sprite.uvs[3] = 0 - offsetY; + + sprite.uvs[4] = (1 *scaleX) - offsetX; + sprite.uvs[5] = (1 *scaleY) - offsetY; + + sprite.uvs[6] = 0 - offsetX; + sprite.uvs[7] = (1 *scaleY) - offsetY; + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) + + this.renderStrip(sprite, projectionMatrix); +} + +/** + * Initializes a strip to be rendered + * + * @method initStrip + * @param strip {Strip} The strip to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) +{ + // build the strip! + var gl = this.gl; + var shaderProgram = this.shaderProgram; + + strip._vertexBuffer = gl.createBuffer(); + strip._indexBuffer = gl.createBuffer(); + strip._uvBuffer = gl.createBuffer(); + strip._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); + + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.WebGLFilterManager = function(transparent) +{ + this.transparent = transparent; + + this.filterStack = []; + this.texturePool = []; + + this.offsetX = 0; + this.offsetY = 0; + + this.initShaderBuffers(); +} + +// API + +PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) +{ + this.width = projection.x * 2; + this.height = -projection.y * 2; + this.buffer = buffer; +} + +PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) +{ + var gl = PIXI.gl; + + // filter program + // OPTIMISATION - the first filter is free if its a simple color change? + this.filterStack.push(filterBlock); + + var filter = filterBlock.filterPasses[0]; + + + + this.offsetX += filterBlock.target.filterArea.x; + this.offsetY += filterBlock.target.filterArea.y; + + + + + + var texture = this.texturePool.pop(); + if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); + + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + this.getBounds(filterBlock.target); + + // addpadding? + //displayObject.filterArea.x + + var filterArea = filterBlock.target.filterArea; + + var padidng = filter.padding; + filterArea.x -= padidng; + filterArea.y -= padidng; + filterArea.width += padidng * 2; + filterArea.height += padidng * 2; + + // cap filter to screen size.. + if(filterArea.x < 0)filterArea.x = 0; + if(filterArea.width > this.width)filterArea.width = this.width; + if(filterArea.y < 0)filterArea.y = 0; + if(filterArea.height > this.height)filterArea.height = this.height; + + + //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); + + // console.log(filterArea) + // set view port + gl.viewport(0, 0, filterArea.width, filterArea.height); + + PIXI.projection.x = filterArea.width/2; + PIXI.projection.y = -filterArea.height/2; + + PIXI.offset.x = -filterArea.x; + PIXI.offset.y = -filterArea.y; + + //console.log(PIXI.defaultShader.projectionVector) + // update projection + gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); + //PIXI.primitiveProgram + + gl.colorMask(true, true, true, true); + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + //filter.texture = texture; + filterBlock._glFilterTexture = texture; + + //console.log("PUSH") +} + + +PIXI.WebGLFilterManager.prototype.popFilter = function() +{ + + var gl = PIXI.gl; + + var filterBlock = this.filterStack.pop(); + + + + var filterArea = filterBlock.target.filterArea; + + var texture = filterBlock._glFilterTexture; + + if(filterBlock.filterPasses.length > 1) + { + gl.viewport(0, 0, filterArea.width, filterArea.height); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = 0; + this.vertexArray[1] = filterArea.height; + + this.vertexArray[2] = filterArea.width; + this.vertexArray[3] = filterArea.height; + + this.vertexArray[4] = 0; + this.vertexArray[5] = 0; + + this.vertexArray[6] = filterArea.width; + this.vertexArray[7] = 0; + + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + // nnow set the uvs.. + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + var inputTexture = texture; + var outputTexture = this.texturePool.pop(); + if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); + + // need to clear this FBO as it may have some left over elements from a prvious filter. + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.disable(gl.BLEND); + + for (var i = 0; i < filterBlock.filterPasses.length-1; i++) + { + var filterPass = filterBlock.filterPasses[i]; + + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); + + // draw texture.. + //filterPass.applyFilterPass(filterArea.width, filterArea.height); + this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); + + // swap the textures.. + var temp = inputTexture; + inputTexture = outputTexture; + outputTexture = temp; + + }; + + gl.enable(gl.BLEND); + + texture = inputTexture; + this.texturePool.push(outputTexture); + } + + var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; + + this.offsetX -= filterArea.x; + this.offsetY -= filterArea.y; + + + var sizeX = this.width; + var sizeY = this.height; + + var offsetX = 0; + var offsetY = 0; + + var buffer = this.buffer; + + // time to render the filters texture to the previous scene + if(this.filterStack.length === 0) + { + gl.colorMask(true, true, true, this.transparent); + } + else + { + var currentFilter = this.filterStack[this.filterStack.length-1]; + var filterArea = currentFilter.target.filterArea; + + sizeX = filterArea.width; + sizeY = filterArea.height; + + offsetX = filterArea.x; + offsetY = filterArea.y; + + buffer = currentFilter._glFilterTexture.frameBuffer; + } + + + + // TODO need toremove thease global elements.. + PIXI.projection.x = sizeX/2; + PIXI.projection.y = -sizeY/2; + + PIXI.offset.x = offsetX; + PIXI.offset.y = offsetY; + + + var filterArea = filterBlock.target.filterArea; + var x = filterArea.x-offsetX; + var y = filterArea.y-offsetY; + + // update the buffers.. + // make sure to flip the y! + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = x; + this.vertexArray[1] = y + filterArea.height; + + this.vertexArray[2] = x + filterArea.width; + this.vertexArray[3] = y + filterArea.height; + + this.vertexArray[4] = x; + this.vertexArray[5] = y; + + this.vertexArray[6] = x + filterArea.width; + this.vertexArray[7] = y; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + gl.viewport(0, 0, sizeX, sizeY); + // bind the buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + // apply! + //filter.applyFilterPass(sizeX, sizeY); + this.applyFilterPass(filter, filterArea, sizeX, sizeY); + + // now restore the regular shader.. + gl.useProgram(PIXI.defaultShader.program); + gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); + + // return the texture to the pool + this.texturePool.push(texture); + filterBlock._glFilterTexture = null; +} + +PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) +{ + // use program + var gl = PIXI.gl; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader; + } + + var shader = filter.shader; + + // set the shader + gl.useProgram(shader.program); + + gl.uniform2f(shader.projectionVector, width/2, -height/2); + gl.uniform2f(shader.offsetVector, 0,0) + + if(filter.uniforms.dimensions) + { + //console.log(filter.uniforms.dimensions) + filter.uniforms.dimensions.value[0] = this.width;//width; + filter.uniforms.dimensions.value[1] = this.height;//height; + filter.uniforms.dimensions.value[2] = this.vertexArray[0]; + filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; + // console.log(this.vertexArray[5]) + } + + shader.syncUniforms(); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + // draw the filter... + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); +} + +PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() +{ + var gl = PIXI.gl; + + // create some buffers + this.vertexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + // bind and upload the vertexs.. + // keep a refferance to the vertexFloatData.. + this.vertexArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.vertexArray, + gl.STATIC_DRAW); + + + // bind and upload the uv buffer + this.uvArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.uvArray, + gl.STATIC_DRAW); + + // bind and upload the index + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData( + gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array([0, 1, 2, 1, 3, 2]), + gl.STATIC_DRAW); +} + +PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) +{ + // time to get the width and height of the object! + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; + var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + + var maxX = -Infinity; + var maxY = -Infinity; + + var minX = Infinity; + var minY = Infinity; + + do + { + // TODO can be optimized! - what if there is no scale / rotation? + + if(tempObject.visible) + { + if(tempObject instanceof PIXI.Sprite) + { + width = tempObject.texture.frame.width; + height = tempObject.texture.frame.height; + + // TODO trim?? + aX = tempObject.anchor.x; + aY = tempObject.anchor.y; + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + doTest = true; + } + else if(tempObject instanceof PIXI.Graphics) + { + tempObject.updateFilterBounds(); + + var bounds = tempObject.bounds; + + width = bounds.width; + height = bounds.height; + + w0 = bounds.x + w1 = bounds.x + bounds.width; + + h0 = bounds.y + h1 = bounds.y + bounds.height; + + doTest = true; + } + } + + if(doTest) + { + worldTransform = tempObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + x1 = a * w1 + c * h1 + tx; + y1 = d * h1 + b * w1 + ty; + + x2 = a * w0 + c * h1 + tx; + y2 = d * h1 + b * w0 + ty; + + x3 = a * w0 + c * h0 + tx; + y3 = d * h0 + b * w0 + ty; + + x4 = a * w1 + c * h0 + tx; + y4 = d * h0 + b * w1 + ty; + + minX = x1 < minX ? x1 : minX; + minX = x2 < minX ? x2 : minX; + minX = x3 < minX ? x3 : minX; + minX = x4 < minX ? x4 : minX; + + minY = y1 < minY ? y1 : minY; + minY = y2 < minY ? y2 : minY; + minY = y3 < minY ? y3 : minY; + minY = y4 < minY ? y4 : minY; + + maxX = x1 > maxX ? x1 : maxX; + maxX = x2 > maxX ? x2 : maxX; + maxX = x3 > maxX ? x3 : maxX; + maxX = x4 > maxX ? x4 : maxX; + + maxY = y1 > maxY ? y1 : maxY; + maxY = y2 > maxY ? y2 : maxY; + maxY = y3 > maxY ? y3 : maxY; + maxY = y4 > maxY ? y4 : maxY; + } + + doTest = false; + tempObject = tempObject._iNext; + + } + while(tempObject != testObject) + + // maximum bounds is the size of the screen.. + //minX = minX > 0 ? minX : 0; + //minY = minY > 0 ? minY : 0; + + displayObject.filterArea.x = minX; + displayObject.filterArea.y = minY; + +// console.log(maxX+ " : " + minX) + displayObject.filterArea.width = maxX - minX; + displayObject.filterArea.height = maxY - minY; +} + +PIXI.FilterTexture = function(width, height) +{ + var gl = PIXI.gl; + + // next time to create a frame buffer and texture + this.frameBuffer = gl.createFramebuffer(); + this.texture = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); + + this.resize(width, height); +} + +PIXI.FilterTexture.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + var gl = PIXI.gl; + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class CanvasRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + */ +PIXI.CanvasRenderer = function(width, height, view, transparent) +{ + this.transparent = transparent; + + /** + * The width of the canvas view + * + * @property width + * @type Number + * @default 800 + */ + this.width = width || 800; + + /** + * The height of the canvas view + * + * @property height + * @type Number + * @default 600 + */ + this.height = height || 600; + + /** + * The canvas element that the everything is drawn to + * + * @property view + * @type Canvas + */ + this.view = view || document.createElement( 'canvas' ); + + /** + * The canvas context that the everything is drawn to + * @property context + * @type Canvas 2d Context + */ + this.context = this.view.getContext("2d"); + + this.refresh = true; + // hack to enable some hardware acceleration! + //this.view.style["transform"] = "translatez(0)"; + + this.view.width = this.width; + this.view.height = this.height; + this.count = 0; +} + +// constructor +PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; + +/** + * Renders the stage to its canvas view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.CanvasRenderer.prototype.render = function(stage) +{ + + //stage.__childrenAdded = []; + //stage.__childrenRemoved = []; + + // update textures if need be + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; + + PIXI.visibleCount++; + stage.updateTransform(); + + // update the background color + if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; + + this.context.setTransform(1,0,0,1,0,0); + this.context.clearRect(0, 0, this.width, this.height) + this.renderDisplayObject(stage); + //as + + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // remove frame updates.. + if(PIXI.Texture.frameUpdates.length > 0) + { + PIXI.Texture.frameUpdates = []; + } + + +} + +/** + * resizes the canvas view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the canvas view + * @param height {Number} the new height of the canvas view + */ +PIXI.CanvasRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; +} + +/** + * Renders a display object + * + * @method renderDisplayObject + * @param displayObject {DisplayObject} The displayObject to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +{ + // no loger recurrsive! + var transform; + var context = this.context; + + context.globalCompositeOperation = 'source-over'; + + // one the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + transform = displayObject.worldTransform; + + if(!displayObject.visible) + { + displayObject = displayObject.last._iNext; + continue; + } + + if(!displayObject.renderable) + { + displayObject = displayObject._iNext; + continue; + } + + if(displayObject instanceof PIXI.Sprite) + { + + var frame = displayObject.texture.frame; + + if(frame && frame.width && frame.height) + { + context.globalAlpha = displayObject.worldAlpha; + + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + + context.drawImage(displayObject.texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.y) * -frame.height, + frame.width, + frame.height); + } + } + else if(displayObject instanceof PIXI.Strip) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderStrip(displayObject); + } + else if(displayObject instanceof PIXI.TilingSprite) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderTilingSprite(displayObject); + } + else if(displayObject instanceof PIXI.CustomRenderable) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + displayObject.renderCanvas(this); + } + else if(displayObject instanceof PIXI.Graphics) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + PIXI.CanvasGraphics.renderGraphics(displayObject, context); + } + else if(displayObject instanceof PIXI.FilterBlock) + { + if(displayObject.data instanceof PIXI.Graphics) + { + var mask = displayObject.data; + + if(displayObject.open) + { + context.save(); + + var cacheAlpha = mask.alpha; + var maskTransform = mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(mask, context); + context.clip(); + + mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } + } + else + { + // only masks supported right now! + } + } + // count++ + displayObject = displayObject._iNext; + + + } + while(displayObject != testObject) + + +} + +/** + * Renders a flat strip + * + * @method renderStripFlat + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) +{ + var context = this.context; + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + + context.beginPath(); + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + }; + + context.fillStyle = "#FF0000"; + context.fill(); + context.closePath(); +} + +/** + * Renders a tiling sprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tilingsprite to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) +{ + var context = this.context; + + context.globalAlpha = sprite.worldAlpha; + + if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); + + context.beginPath(); + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + // offset + context.scale(tileScale.x,tileScale.y); + context.translate(tilePosition.x, tilePosition.y); + + context.fillStyle = sprite.__tilePattern; + context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); + + context.scale(1/tileScale.x, 1/tileScale.y); + context.translate(-tilePosition.x, -tilePosition.y); + + context.closePath(); +} + +/** + * Renders a strip + * + * @method renderStrip + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStrip = function(strip) +{ + var context = this.context; + + // draw triangles!! + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; + var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; + + + context.save(); + context.beginPath(); + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + context.closePath(); + + context.clip(); + + + // Compute matrix transform + var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; + var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; + var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; + var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; + var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; + var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; + var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; + + + + + context.transform(delta_a/delta, delta_d/delta, + delta_b/delta, delta_e/delta, + delta_c/delta, delta_f/delta); + + context.drawImage(strip.texture.baseTexture.source, 0, 0); + context.restore(); + }; + +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A set of functions used by the canvas renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.CanvasGraphics = function() +{ + +} + + +/* + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphics = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + for (var i=0; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); + + context.lineWidth = data.lineWidth; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + + if(data.fillColor || data.fillColor === 0) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fillRect(points[0], points[1], points[2], points[3]); + + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.strokeRect(points[0], points[1], points[2], points[3]); + } + + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + + }; +} + +/* + * Renders a graphics mask + * + * @static + * @private + * @method renderGraphicsMask + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + var len = graphics.graphicsData.length; + if(len === 0)return; + + if(len > 1) + { + len = 1; + console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") + } + + for (var i=0; i < 1; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + } + else if(data.type == PIXI.Graphics.RECT) + { + context.beginPath(); + context.rect(points[0], points[1], points[2], points[3]); + context.closePath(); + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + + + }; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * It is important to know that with the webGL renderer only simple polys can be filled at this stage + * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png + * + * @class Graphics + * @extends DisplayObjectContainer + * @constructor + */ +PIXI.Graphics = function() +{ + PIXI.DisplayObjectContainer.call( this ); + + this.renderable = true; + + /** + * The alpha of the fill of this graphics object + * + * @property fillAlpha + * @type Number + */ + this.fillAlpha = 1; + + /** + * The width of any lines drawn + * + * @property lineWidth + * @type Number + */ + this.lineWidth = 0; + + /** + * The color of any lines drawn + * + * @property lineColor + * @type String + */ + this.lineColor = "black"; + + /** + * Graphics data + * + * @property graphicsData + * @type Array + * @private + */ + this.graphicsData = []; + + /** + * Current path + * + * @property currentPath + * @type Object + * @private + */ + this.currentPath = {points:[]}; +} + +// constructor +PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Graphics.prototype.constructor = PIXI.Graphics; + +/** + * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. + * + * @method lineStyle + * @param lineWidth {Number} width of the line to draw, will update the object's stored style + * @param color {Number} color of the line to draw, will update the object's stored style + * @param alpha {Number} alpha of the line to draw, will update the object's stored style + */ +PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.lineWidth = lineWidth || 0; + this.lineColor = color || 0; + this.lineAlpha = (alpha == undefined) ? 1 : alpha; + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.graphicsData.push(this.currentPath); +} + +/** + * Moves the current drawing position to (x, y). + * + * @method moveTo + * @param x {Number} the X coord to move to + * @param y {Number} the Y coord to move to + */ +PIXI.Graphics.prototype.moveTo = function(x, y) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.currentPath.points.push(x, y); + + this.graphicsData.push(this.currentPath); +} + +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coord to draw to + * @param y {Number} the Y coord to draw to + */ +PIXI.Graphics.prototype.lineTo = function(x, y) +{ + this.currentPath.points.push(x, y); + this.dirty = true; +} + +/** + * Specifies a simple one-color fill that subsequent calls to other Graphics methods + * (such as lineTo() or drawCircle()) use when drawing. + * + * @method beginFill + * @param color {uint} the color of the fill + * @param alpha {Number} the alpha + */ +PIXI.Graphics.prototype.beginFill = function(color, alpha) +{ + this.filling = true; + this.fillColor = color || 0; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; +} + +/** + * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. + * + * @method endFill + */ +PIXI.Graphics.prototype.endFill = function() +{ + this.filling = false; + this.fillColor = null; + this.fillAlpha = 1; +} + +/** + * @method drawRect + * + * @param x {Number} The X coord of the top-left of the rectangle + * @param y {Number} The Y coord of the top-left of the rectangle + * @param width {Number} The width of the rectangle + * @param height {Number} The height of the rectangle + */ +PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.RECT}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws a circle. + * + * @method drawCircle + * @param x {Number} The X coord of the center of the circle + * @param y {Number} The Y coord of the center of the circle + * @param radius {Number} The radius of the circle + */ +PIXI.Graphics.prototype.drawCircle = function( x, y, radius) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws an elipse. + * + * @method drawElipse + * @param x {Number} + * @param y {Number} + * @param width {Number} + * @param height {Number} + */ +PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.ELIP}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. + * + * @method clear + */ +PIXI.Graphics.prototype.clear = function() +{ + this.lineWidth = 0; + this.filling = false; + + this.dirty = true; + this.clearDirty = true; + this.graphicsData = []; + + this.bounds = null//new PIXI.Rectangle(); +} + + +PIXI.Graphics.prototype.updateFilterBounds = function() +{ + if(!this.bounds) + { + var minX = Infinity; + var maxX = -Infinity; + + var minY = Infinity; + var maxY = -Infinity; + + var points, x, y; + + for (var i = 0; i < this.graphicsData.length; i++) { + + + var data = this.graphicsData[i]; + var type = data.type; + var lineWidth = data.lineWidth; + + points = data.points; + + if(type === PIXI.Graphics.RECT) + { + x = points.x - lineWidth/2; + y = points.y - lineWidth/2; + var width = points.width + lineWidth; + var height = points.height + lineWidth; + + minX = x < minX ? x : minX; + maxX = x + width > maxX ? x + width : maxX; + + minY = y < minY ? x : minY; + maxY = y + height > maxY ? y + height : maxY; + } + else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + { + x = points.x; + y = points.y; + var radius = points.radius + lineWidth/2; + + minX = x - radius < minX ? x - radius : minX; + maxX = x + radius > maxX ? x + radius : maxX; + + minY = y - radius < minY ? y - radius : minY; + maxY = y + radius > maxY ? y + radius : maxY; + } + else + { + // POLY + for (var j = 0; j < points.length; j+=2) + { + + x = points[j]; + y = points[j+1]; + + minX = x-lineWidth < minX ? x-lineWidth : minX; + maxX = x+lineWidth > maxX ? x+lineWidth : maxX; + + minY = y-lineWidth < minY ? y-lineWidth : minY; + maxY = y+lineWidth > maxY ? y+lineWidth : maxY; + }; + } + + }; + + this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + + } + +// console.log(this.bounds); +} + +// SOME TYPES: +PIXI.Graphics.POLY = 0; +PIXI.Graphics.RECT = 1; +PIXI.Graphics.CIRC = 2; +PIXI.Graphics.ELIP = 3; + +/** + * @author Mat Groves http://matgroves.com/ + */ + +PIXI.Strip = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + this.texture = texture; + this.blendMode = PIXI.blendModes.NORMAL; + + try + { + this.uvs = new Float32Array([0, 1, + 1, 1, + 1, 0, 0,1]); + + this.verticies = new Float32Array([0, 0, + 0,0, + 0,0, 0, + 0, 0]); + + this.colors = new Float32Array([1, 1, 1, 1]); + + this.indices = new Uint16Array([0, 1, 2, 3]); + } + catch(error) + { + this.uvs = [0, 1, + 1, 1, + 1, 0, 0,1]; + + this.verticies = [0, 0, + 0,0, + 0,0, 0, + 0, 0]; + + this.colors = [1, 1, 1, 1]; + + this.indices = [0, 1, 2, 3]; + } + + + /* + this.uvs = new Float32Array() + this.verticies = new Float32Array() + this.colors = new Float32Array() + this.indices = new Uint16Array() +*/ + this.width = width; + this.height = height; + + // load the texture! + if(texture.baseTexture.hasLoaded) + { + this.width = this.texture.frame.width; + this.height = this.texture.frame.height; + this.updateFrame = true; + } + else + { + this.onTextureUpdateBind = this.onTextureUpdate.bind(this); + this.texture.addEventListener( 'update', this.onTextureUpdateBind ); + } + + this.renderable = true; +} + +// constructor +PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Strip.prototype.constructor = PIXI.Strip; + +PIXI.Strip.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.width = texture.frame.width; + this.height = texture.frame.height; + this.updateFrame = true; +} + +PIXI.Strip.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} +// some helper functions.. + + +/** + * @author Mat Groves http://matgroves.com/ + */ + + +PIXI.Rope = function(texture, points) +{ + PIXI.Strip.call( this, texture ); + this.points = points; + + try + { + this.verticies = 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); + } + catch(error) + { + this.verticies = verticies + + this.uvs = uvs + this.colors = colors + this.indices = indices + } + + this.refresh(); +} + + +// constructor +PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); +PIXI.Rope.prototype.constructor = PIXI.Rope; + +PIXI.Rope.prototype.refresh = function() +{ + var points = this.points; + if(points.length < 1)return; + + var uvs = this.uvs + var indices = this.indices; + var colors = this.colors; + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + + uvs[0] = 0 + uvs[1] = 1 + uvs[2] = 0 + uvs[3] = 1 + + colors[0] = 1; + colors[1] = 1; + + indices[0] = 0; + indices[1] = 1; + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + // time to do some smart drawing! + var amount = i/(total-1) + + if(i%2) + { + uvs[index] = amount; + uvs[index+1] = 0; + + uvs[index+2] = amount + uvs[index+3] = 1 + + } + else + { + uvs[index] = amount + uvs[index+1] = 0 + + uvs[index+2] = amount + uvs[index+3] = 1 + } + + index = i * 2; + colors[index] = 1; + colors[index+1] = 1; + + index = i * 2; + indices[index] = index; + indices[index + 1] = index + 1; + + lastPoint = point; + } +} + +PIXI.Rope.prototype.updateTransform = function() +{ + + var points = this.points; + if(points.length < 1)return; + + var verticies = this.verticies + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + verticies[0] = point.x + perp.x + verticies[1] = point.y + perp.y //+ 200 + verticies[2] = point.x - perp.x + verticies[3] = point.y - perp.y//+200 + // time to do some smart drawing! + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + + if(i < points.length-1) + { + nextPoint = points[i+1]; + } + else + { + nextPoint = point + } + + perp.y = -(nextPoint.x - lastPoint.x); + perp.x = nextPoint.y - lastPoint.y; + + var ratio = (1 - (i / (total-1))) * 10; + if(ratio > 1)ratio = 1; + + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); + var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; + perp.x /= perpLength; + perp.y /= perpLength; + + perp.x *= num; + perp.y *= num; + + verticies[index] = point.x + perp.x + verticies[index+1] = point.y + perp.y + verticies[index+2] = point.x - perp.x + verticies[index+3] = point.y - perp.y + + lastPoint = point; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); +} + +PIXI.Rope.prototype.setTexture = function(texture) +{ + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * A tiling sprite is a fast way of rendering a tiling image + * + * @class TilingSprite + * @extends DisplayObjectContainer + * @constructor + * @param texture {Texture} the texture of the tiling sprite + * @param width {Number} the width of the tiling sprite + * @param height {Number} the height of the tiling sprite + */ +PIXI.TilingSprite = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * The texture that the sprite is using + * + * @property texture + * @type Texture + */ + this.texture = texture; + + /** + * The width of the tiling sprite + * + * @property width + * @type Number + */ + this.width = width; + + /** + * The height of the tiling sprite + * + * @property height + * @type Number + */ + this.height = height; + + /** + * The scaling of the image that is being tiled + * + * @property tileScale + * @type Point + */ + this.tileScale = new PIXI.Point(1,1); + + /** + * The offset position of the image that is being tiled + * + * @property tilePosition + * @type Point + */ + this.tilePosition = new PIXI.Point(0,0); + + this.renderable = true; + + this.blendMode = PIXI.blendModes.NORMAL +} + +// constructor +PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; + +/** + * Sets the texture of the tiling sprite + * + * @method setTexture + * @param texture {Texture} The PIXI texture that is displayed by the sprite + */ +PIXI.TilingSprite.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + +/** + * When the texture is updated, this event will fire to update the frame + * + * @method onTextureUpdate + * @param event + * @private + */ +PIXI.TilingSprite.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi + * + * Awesome JS run time provided by EsotericSoftware + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +/** + * A class that enables the you to import and run your spine animations in pixi. + * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class + * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source + * + * @class Spine + * @extends DisplayObjectContainer + * @constructor + * @param url {String} The url of the spine anim file to be used + */ +PIXI.Spine = function (url) { + PIXI.DisplayObjectContainer.call(this); + + this.spineData = PIXI.AnimCache[url]; + + if (!this.spineData) { + throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); + } + + this.skeleton = new spine.Skeleton(this.spineData); + this.skeleton.updateWorldTransform(); + + this.stateData = new spine.AnimationStateData(this.spineData); + this.state = new spine.AnimationState(this.stateData); + + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.Spine.prototype.constructor = PIXI.Spine; + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); + this.state.apply(this.skeleton); + this.skeleton.updateWorldTransform(); + + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } + + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; + } + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; + } + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; + +/* + * Awesome JS run time provided by EsotericSoftware + * + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +var spine = {}; + +spine.BoneData = function (name, parent) { + this.name = name; + this.parent = parent; +}; +spine.BoneData.prototype = { + length: 0, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1 +}; + +spine.SlotData = function (name, boneData) { + this.name = name; + this.boneData = boneData; +}; +spine.SlotData.prototype = { + r: 1, g: 1, b: 1, a: 1, + attachmentName: null +}; + +spine.Bone = function (boneData, parent) { + this.data = boneData; + this.parent = parent; + this.setToSetupPose(); +}; +spine.Bone.yDown = false; +spine.Bone.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + m00: 0, m01: 0, worldX: 0, // a b x + m10: 0, m11: 0, worldY: 0, // c d y + worldRotation: 0, + worldScaleX: 1, worldScaleY: 1, + updateWorldTransform: function (flipX, flipY) { + var parent = this.parent; + if (parent != null) { + this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; + this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; + this.worldScaleX = parent.worldScaleX * this.scaleX; + this.worldScaleY = parent.worldScaleY * this.scaleY; + this.worldRotation = parent.worldRotation + this.rotation; + } else { + this.worldX = this.x; + this.worldY = this.y; + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + this.worldRotation = this.rotation; + } + var radians = this.worldRotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + this.m00 = cos * this.worldScaleX; + this.m10 = sin * this.worldScaleX; + this.m01 = -sin * this.worldScaleY; + this.m11 = cos * this.worldScaleY; + if (flipX) { + this.m00 = -this.m00; + this.m01 = -this.m01; + } + if (flipY) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + if (spine.Bone.yDown) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + }, + setToSetupPose: function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + } +}; + +spine.Slot = function (slotData, skeleton, bone) { + this.data = slotData; + this.skeleton = skeleton; + this.bone = bone; + this.setToSetupPose(); +}; +spine.Slot.prototype = { + r: 1, g: 1, b: 1, a: 1, + _attachmentTime: 0, + attachment: null, + setAttachment: function (attachment) { + this.attachment = attachment; + this._attachmentTime = this.skeleton.time; + }, + setAttachmentTime: function (time) { + this._attachmentTime = this.skeleton.time - time; + }, + getAttachmentTime: function () { + return this.skeleton.time - this._attachmentTime; + }, + setToSetupPose: function () { + var data = this.data; + this.r = data.r; + this.g = data.g; + this.b = data.b; + this.a = data.a; + + var slotDatas = this.skeleton.data.slots; + for (var i = 0, n = slotDatas.length; i < n; i++) { + if (slotDatas[i] == data) { + this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); + break; + } + } + } +}; + +spine.Skin = function (name) { + this.name = name; + this.attachments = {}; +}; +spine.Skin.prototype = { + addAttachment: function (slotIndex, name, attachment) { + this.attachments[slotIndex + ":" + name] = attachment; + }, + getAttachment: function (slotIndex, name) { + return this.attachments[slotIndex + ":" + name]; + }, + _attachAll: function (skeleton, oldSkin) { + for (var key in oldSkin.attachments) { + var colon = key.indexOf(":"); + var slotIndex = parseInt(key.substring(0, colon)); + var name = key.substring(colon + 1); + var slot = skeleton.slots[slotIndex]; + if (slot.attachment && slot.attachment.name == name) { + var attachment = this.getAttachment(slotIndex, name); + if (attachment) slot.setAttachment(attachment); + } + } + } +}; + +spine.Animation = function (name, timelines, duration) { + this.name = name; + this.timelines = timelines; + this.duration = duration; +}; +spine.Animation.prototype = { + apply: function (skeleton, time, loop) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, 1); + }, + mix: function (skeleton, time, loop, alpha) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, alpha); + } +}; + +spine.binarySearch = function (values, target, step) { + var low = 0; + var high = Math.floor(values.length / step) - 2; + if (high == 0) return step; + var current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } +}; +spine.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; +}; + +spine.Curves = function (frameCount) { + this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... + this.curves.length = (frameCount - 1) * 6; +}; +spine.Curves.prototype = { + setLinear: function (frameIndex) { + this.curves[frameIndex * 6] = 0/*LINEAR*/; + }, + setStepped: function (frameIndex) { + this.curves[frameIndex * 6] = -1/*STEPPED*/; + }, + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { + var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; + var subdiv_step2 = subdiv_step * subdiv_step; + var subdiv_step3 = subdiv_step2 * subdiv_step; + var pre1 = 3 * subdiv_step; + var pre2 = 3 * subdiv_step2; + var pre4 = 6 * subdiv_step2; + var pre5 = 6 * subdiv_step3; + var tmp1x = -cx1 * 2 + cx2; + var tmp1y = -cy1 * 2 + cy2; + var tmp2x = (cx1 - cx2) * 3 + 1; + var tmp2y = (cy1 - cy2) * 3 + 1; + var i = frameIndex * 6; + var curves = this.curves; + curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; + curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; + curves[i + 4] = tmp2x * pre5; + curves[i + 5] = tmp2y * pre5; + }, + getCurvePercent: function (frameIndex, percent) { + percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); + var curveIndex = frameIndex * 6; + var curves = this.curves; + var dfx = curves[curveIndex]; + if (!dfx/*LINEAR*/) return percent; + if (dfx == -1/*STEPPED*/) return 0; + var dfy = curves[curveIndex + 1]; + var ddfx = curves[curveIndex + 2]; + var ddfy = curves[curveIndex + 3]; + var dddfx = curves[curveIndex + 4]; + var dddfy = curves[curveIndex + 5]; + var x = dfx, y = dfy; + var i = 10/*BEZIER_SEGMENTS*/ - 2; + while (true) { + if (x >= percent) { + var lastX = x - dfx; + var lastY = y - dfy; + return lastY + (y - lastY) * (percent - lastX) / (x - lastX); + } + if (i == 0) break; + i--; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +}; + +spine.RotateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, angle, ... + this.frames.length = frameCount * 2; +}; +spine.RotateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, angle) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = angle; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 2]) { // Time is after last frame. + var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 2); + var lastFrameValue = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); + + var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +}; + +spine.TranslateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.TranslateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; + } +}; + +spine.ScaleTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.ScaleTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; + } +}; + +spine.ColorTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, r, g, b, a, ... + this.frames.length = frameCount * 5; +}; +spine.ColorTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 5; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = r; + this.frames[frameIndex + 2] = g; + this.frames[frameIndex + 3] = b; + this.frames[frameIndex + 4] = a; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var slot = skeleton.slots[this.slotIndex]; + + if (time >= frames[frames.length - 5]) { // Time is after last frame. + var i = frames.length - 1; + slot.r = frames[i - 3]; + slot.g = frames[i - 2]; + slot.b = frames[i - 1]; + slot.a = frames[i]; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 5); + var lastFrameR = frames[frameIndex - 4]; + var lastFrameG = frames[frameIndex - 3]; + var lastFrameB = frames[frameIndex - 2]; + var lastFrameA = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); + + var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; + var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; + var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; + var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +}; + +spine.AttachmentTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, ... + this.frames.length = frameCount; + this.attachmentNames = []; // time, ... + this.attachmentNames.length = frameCount; +}; +spine.AttachmentTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = spine.binarySearch(frames, time, 1) - 1; + + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); + } +}; + +spine.SkeletonData = function () { + this.bones = []; + this.slots = []; + this.skins = []; + this.animations = []; +}; +spine.SkeletonData.prototype = { + defaultSkin: null, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + if (slots[i].name == slotName) return slot[i]; + } + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + }, + /** @return May be null. */ + findSkin: function (skinName) { + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) + if (skins[i].name == skinName) return skins[i]; + return null; + }, + /** @return May be null. */ + findAnimation: function (animationName) { + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) + if (animations[i].name == animationName) return animations[i]; + return null; + } +}; + +spine.Skeleton = function (skeletonData) { + this.data = skeletonData; + + this.bones = []; + for (var i = 0, n = skeletonData.bones.length; i < n; i++) { + var boneData = skeletonData.bones[i]; + var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; + this.bones.push(new spine.Bone(boneData, parent)); + } + + this.slots = []; + this.drawOrder = []; + for (var i = 0, n = skeletonData.slots.length; i < n; i++) { + var slotData = skeletonData.slots[i]; + var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; + var slot = new spine.Slot(slotData, this, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } +}; +spine.Skeleton.prototype = { + x: 0, y: 0, + skin: null, + r: 1, g: 1, b: 1, a: 1, + time: 0, + flipX: false, flipY: false, + /** Updates the world transform for each bone. */ + updateWorldTransform: function () { + var flipX = this.flipX; + var flipY = this.flipY; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].updateWorldTransform(flipX, flipY); + }, + /** Sets the bones and slots to their setup pose values. */ + setToSetupPose: function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }, + setBonesToSetupPose: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + }, + setSlotsToSetupPose: function () { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(i); + }, + /** @return May return null. */ + getRootBone: function () { + return this.bones.length == 0 ? null : this.bones[0]; + }, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return slots[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + }, + setSkinByName: function (skinName) { + var skin = this.data.findSkin(skinName); + if (!skin) throw "Skin not found: " + skinName; + this.setSkin(skin); + }, + /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments + * from the new skin are attached if the corresponding attachment from the old skin was attached. + * @param newSkin May be null. */ + setSkin: function (newSkin) { + if (this.skin && newSkin) newSkin._attachAll(this, this.skin); + this.skin = newSkin; + }, + /** @return May be null. */ + getAttachmentBySlotName: function (slotName, attachmentName) { + return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); + }, + /** @return May be null. */ + getAttachmentBySlotIndex: function (slotIndex, attachmentName) { + if (this.skin) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }, + /** @param attachmentName May be null. */ + setAttachment: function (slotName, attachmentName) { + var slots = this.slots; + for (var i = 0, n = slots.size; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; + } + slot.setAttachment(attachment); + return; + } + } + throw "Slot not found: " + slotName; + }, + update: function (delta) { + time += delta; + } +}; + +spine.AttachmentType = { + region: 0 +}; + +spine.RegionAttachment = function () { + this.offset = []; + this.offset.length = 8; + this.uvs = []; + this.uvs.length = 8; +}; +spine.RegionAttachment.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + width: 0, height: 0, + rendererObject: null, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + setUVs: function (u, v, u2, v2, rotate) { + var uvs = this.uvs; + if (rotate) { + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v2; + uvs[4/*X3*/] = u; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v; + uvs[0/*X1*/] = u2; + uvs[1/*Y1*/] = v2; + } else { + uvs[0/*X1*/] = u; + uvs[1/*Y1*/] = v2; + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v; + uvs[4/*X3*/] = u2; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v2; + } + }, + updateOffset: function () { + var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; + var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; + var localX2 = localX + this.regionWidth * regionScaleX; + var localY2 = localY + this.regionHeight * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[0/*X1*/] = localXCos - localYSin; + offset[1/*Y1*/] = localYCos + localXSin; + offset[2/*X2*/] = localXCos - localY2Sin; + offset[3/*Y2*/] = localY2Cos + localXSin; + offset[4/*X3*/] = localX2Cos - localY2Sin; + offset[5/*Y3*/] = localY2Cos + localX2Sin; + offset[6/*X4*/] = localX2Cos - localYSin; + offset[7/*Y4*/] = localYCos + localX2Sin; + }, + computeVertices: function (x, y, bone, vertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00; + var m01 = bone.m01; + var m10 = bone.m10; + var m11 = bone.m11; + var offset = this.offset; + vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; + vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; + vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; + vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; + vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; + vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; + vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; + vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; + } +} + +spine.AnimationStateData = function (skeletonData) { + this.skeletonData = skeletonData; + this.animationToMixTime = {}; +}; +spine.AnimationStateData.prototype = { + defaultMix: 0, + setMixByName: function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (!from) throw "Animation not found: " + fromName; + var to = this.skeletonData.findAnimation(toName); + if (!to) throw "Animation not found: " + toName; + this.setMix(from, to, duration); + }, + setMix: function (from, to, duration) { + this.animationToMixTime[from.name + ":" + to.name] = duration; + }, + getMix: function (from, to) { + var time = this.animationToMixTime[from.name + ":" + to.name]; + return time ? time : this.defaultMix; + } +}; + +spine.AnimationState = function (stateData) { + this.data = stateData; + this.queue = []; +}; +spine.AnimationState.prototype = { + current: null, + previous: null, + currentTime: 0, + previousTime: 0, + currentLoop: false, + previousLoop: false, + mixTime: 0, + mixDuration: 0, + update: function (delta) { + this.currentTime += delta; + this.previousTime += delta; + this.mixTime += delta; + + if (this.queue.length > 0) { + var entry = this.queue[0]; + if (this.currentTime >= entry.delay) { + this._setAnimation(entry.animation, entry.loop); + this.queue.shift(); + } + } + }, + apply: function (skeleton) { + if (!this.current) return; + if (this.previous) { + this.previous.apply(skeleton, this.previousTime, this.previousLoop); + var alpha = this.mixTime / this.mixDuration; + if (alpha >= 1) { + alpha = 1; + this.previous = null; + } + this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); + } else + this.current.apply(skeleton, this.currentTime, this.currentLoop); + }, + clearAnimation: function () { + this.previous = null; + this.current = null; + this.queue.length = 0; + }, + _setAnimation: function (animation, loop) { + this.previous = null; + if (animation && this.current) { + this.mixDuration = this.data.getMix(this.current, animation); + if (this.mixDuration > 0) { + this.mixTime = 0; + this.previous = this.current; + this.previousTime = this.currentTime; + this.previousLoop = this.currentLoop; + } + } + this.current = animation; + this.currentLoop = loop; + this.currentTime = 0; + }, + /** @see #setAnimation(Animation, Boolean) */ + setAnimationByName: function (animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.setAnimation(animation, loop); + }, + /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. + * @param animation May be null. */ + setAnimation: function (animation, loop) { + this.queue.length = 0; + this._setAnimation(animation, loop); + }, + /** @see #addAnimation(Animation, Boolean, Number) */ + addAnimationByName: function (animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.addAnimation(animation, loop, delay); + }, + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimation: function (animation, loop, delay) { + var entry = {}; + entry.animation = animation; + entry.loop = loop; + + if (!delay || delay <= 0) { + var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; + if (previousAnimation != null) + delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); + else + delay = 0; + } + entry.delay = delay; + + this.queue.push(entry); + }, + /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ + isComplete: function () { + return !this.current || this.currentTime >= this.current.duration; + } +}; + +spine.SkeletonJson = function (attachmentLoader) { + this.attachmentLoader = attachmentLoader; +}; +spine.SkeletonJson.prototype = { + scale: 1, + readSkeletonData: function (root) { + var skeletonData = new spine.SkeletonData(); + + // Bones. + var bones = root["bones"]; + for (var i = 0, n = bones.length; i < n; i++) { + var boneMap = bones[i]; + var parent = null; + if (boneMap["parent"]) { + parent = skeletonData.findBone(boneMap["parent"]); + if (!parent) throw "Parent bone not found: " + boneMap["parent"]; + } + var boneData = new spine.BoneData(boneMap["name"], parent); + boneData.length = (boneMap["length"] || 0) * this.scale; + boneData.x = (boneMap["x"] || 0) * this.scale; + boneData.y = (boneMap["y"] || 0) * this.scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap["scaleX"] || 1; + boneData.scaleY = boneMap["scaleY"] || 1; + skeletonData.bones.push(boneData); + } + + // Slots. + var slots = root["slots"]; + for (var i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + var boneData = skeletonData.findBone(slotMap["bone"]); + if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; + var slotData = new spine.SlotData(slotMap["name"], boneData); + + var color = slotMap["color"]; + if (color) { + slotData.r = spine.SkeletonJson.toColor(color, 0); + slotData.g = spine.SkeletonJson.toColor(color, 1); + slotData.b = spine.SkeletonJson.toColor(color, 2); + slotData.a = spine.SkeletonJson.toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + + skeletonData.slots.push(slotData); + } + + // Skins. + var skins = root["skins"]; + for (var skinName in skins) { + if (!skins.hasOwnProperty(skinName)) continue; + var skinMap = skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + if (!skinMap.hasOwnProperty(slotName)) continue; + var slotIndex = skeletonData.findSlotIndex(slotName); + var slotEntry = skinMap[slotName]; + for (var attachmentName in slotEntry) { + if (!slotEntry.hasOwnProperty(attachmentName)) continue; + var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); + if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + + // Animations. + var animations = root["animations"]; + for (var animationName in animations) { + if (!animations.hasOwnProperty(animationName)) continue; + this.readAnimation(animationName, animations[animationName], skeletonData); + } + + return skeletonData; + }, + readAttachment: function (skin, name, map) { + name = map["name"] || name; + + var type = spine.AttachmentType[map["type"] || "region"]; + + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); + attachment.x = (map["x"] || 0) * this.scale; + attachment.y = (map["y"] || 0) * this.scale; + attachment.scaleX = map["scaleX"] || 1; + attachment.scaleY = map["scaleY"] || 1; + attachment.rotation = map["rotation"] || 0; + attachment.width = (map["width"] || 32) * this.scale; + attachment.height = (map["height"] || 32) * this.scale; + attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; + } + + throw "Unknown attachment type: " + type; + }, + + readAnimation: function (name, map, skeletonData) { + var timelines = []; + var duration = 0; + + var bones = map["bones"]; + for (var boneName in bones) { + if (!bones.hasOwnProperty(boneName)) continue; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw "Bone not found: " + boneName; + var boneMap = bones[boneName]; + + for (var timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + var values = boneMap[timelineName]; + if (timelineName == "rotate") { + var timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + + } else if (timelineName == "translate" || timelineName == "scale") { + var timeline; + var timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var x = (valueMap["x"] || 0) * timelineScale; + var y = (valueMap["y"] || 0) * timelineScale; + timeline.setFrame(frameIndex, valueMap["time"], x, y); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); + + } else + throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; + } + } + var slots = map["slots"]; + for (var slotName in slots) { + if (!slots.hasOwnProperty(slotName)) continue; + var slotMap = slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + + for (var timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + var values = slotMap[timelineName]; + if (timelineName == "color") { + var timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var color = valueMap["color"]; + var r = spine.SkeletonJson.toColor(color, 0); + var g = spine.SkeletonJson.toColor(color, 1); + var b = spine.SkeletonJson.toColor(color, 2); + var a = spine.SkeletonJson.toColor(color, 3); + timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); + + } else if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + + } else + throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; + } + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + } +}; +spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { + var curve = valueMap["curve"]; + if (!curve) return; + if (curve == "stepped") + timeline.curves.setStepped(frameIndex); + else if (curve instanceof Array) + timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); +}; +spine.SkeletonJson.toColor = function (hexString, colorIndex) { + if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; + return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; +}; + +spine.Atlas = function (atlasText, textureLoader) { + this.textureLoader = textureLoader; + this.pages = []; + this.regions = []; + + var reader = new spine.AtlasReader(atlasText); + var tuple = []; + tuple.length = 4; + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) break; + line = reader.trim(line); + if (line.length == 0) + page = null; + else if (!page) { + page = new spine.AtlasPage(); + page.name = line; + + page.format = spine.Atlas.Format[reader.readValue()]; + + reader.readTuple(tuple); + page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; + page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; + + var direction = reader.readValue(); + page.uWrap = spine.Atlas.TextureWrap.clampToEdge; + page.vWrap = spine.Atlas.TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "y") + page.vWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; + + textureLoader.load(page, line); + + this.pages.push(page); + + } else { + var region = new spine.AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + this.regions.push(region); + } + } +}; +spine.Atlas.prototype = { + findRegion: function (name) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + }, + dispose: function () { + var pages = this.pages; + for (var i = 0, n = pages.length; i < n; i++) + this.textureLoader.unload(pages[i].rendererObject); + }, + updateUVs: function (page) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) { + var region = regions[i]; + if (region.page != page) continue; + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.rotate) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + } + } +}; + +spine.Atlas.Format = { + alpha: 0, + intensity: 1, + luminanceAlpha: 2, + rgb565: 3, + rgba4444: 4, + rgb888: 5, + rgba8888: 6 +}; + +spine.Atlas.TextureFilter = { + nearest: 0, + linear: 1, + mipMap: 2, + mipMapNearestNearest: 3, + mipMapLinearNearest: 4, + mipMapNearestLinear: 5, + mipMapLinearLinear: 6 +}; + +spine.Atlas.TextureWrap = { + mirroredRepeat: 0, + clampToEdge: 1, + repeat: 2 +}; + +spine.AtlasPage = function () {}; +spine.AtlasPage.prototype = { + name: null, + format: null, + minFilter: null, + magFilter: null, + uWrap: null, + vWrap: null, + rendererObject: null, + width: 0, + height: 0 +}; + +spine.AtlasRegion = function () {}; +spine.AtlasRegion.prototype = { + page: null, + name: null, + x: 0, y: 0, + width: 0, height: 0, + u: 0, v: 0, u2: 0, v2: 0, + offsetX: 0, offsetY: 0, + originalWidth: 0, originalHeight: 0, + index: 0, + rotate: false, + splits: null, + pads: null, +}; + +spine.AtlasReader = function (text) { + this.lines = text.split(/\r\n|\r|\n/); +}; +spine.AtlasReader.prototype = { + index: 0, + trim: function (value) { + return value.replace(/^\s+|\s+$/g, ""); + }, + readLine: function () { + if (this.index >= this.lines.length) return null; + return this.lines[this.index++]; + }, + readValue: function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + return this.trim(line.substring(colon + 1)); + }, + /** Returns the number of tuple values read (2 or 4). */ + readTuple: function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + var i = 0, lastMatch= colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) { + if (i == 0) throw "Invalid line: " + line; + break; + } + tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = this.trim(line.substring(lastMatch)); + return i + 1; + } +} + +spine.AtlasAttachmentLoader = function (atlas) { + this.atlas = atlas; +} +spine.AtlasAttachmentLoader.prototype = { + newAttachment: function (skin, type, name) { + switch (type) { + case spine.AttachmentType.region: + var region = this.atlas.findRegion(name); + if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; + var attachment = new spine.RegionAttachment(name); + attachment.rendererObject = region; + attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + throw "Unknown attachment type: " + type; + } +} + +PIXI.AnimCache = {}; +spine.Bone.yDown = true; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * This object is one that will allow you to specify custom rendering functions based on render type + * + * @class CustomRenderable + * @extends DisplayObject + * @constructor + */ +PIXI.CustomRenderable = function() +{ + PIXI.DisplayObject.call( this ); + + this.renderable = true; +} + +// constructor +PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; + +/** + * If this object is being rendered by a CanvasRenderer it will call this callback + * + * @method renderCanvas + * @param renderer {CanvasRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback to initialize + * + * @method initWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.initWebGL = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback + * + * @method renderWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) +{ + // not sure if both needed? but ya have for now! + // override! +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.BaseTextureCache = {}; +PIXI.texturesToUpdate = []; +PIXI.texturesToDestroy = []; + +/** + * A texture stores the information that represents an image. All textures have a base texture + * + * @class BaseTexture + * @uses EventTarget + * @constructor + * @param source {String} the source object (image or canvas) + */ +PIXI.BaseTexture = function(source) +{ + PIXI.EventTarget.call( this ); + + /** + * [read-only] The width of the base texture set when the image has loaded + * + * @property width + * @type Number + * @readOnly + */ + this.width = 100; + + /** + * [read-only] The height of the base texture set when the image has loaded + * + * @property height + * @type Number + * @readOnly + */ + this.height = 100; + + /** + * [read-only] Describes if the base texture has loaded or not + * + * @property hasLoaded + * @type Boolean + * @readOnly + */ + this.hasLoaded = false; + + /** + * The source that is loaded to create the texture + * + * @property source + * @type Image + */ + this.source = source; + + if(!source)return; + + if(this.source instanceof Image || this.source instanceof HTMLImageElement) + { + if(this.source.complete) + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + else + { + + var scope = this; + this.source.onload = function(){ + + scope.hasLoaded = true; + scope.width = scope.source.width; + scope.height = scope.source.height; + + // add it to somewhere... + PIXI.texturesToUpdate.push(scope); + scope.dispatchEvent( { type: 'loaded', content: scope } ); + } + // this.image.src = imageUrl; + } + } + else + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + + this._powerOf2 = false; +} + +PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; + +/** + * Destroys this base texture + * + * @method destroy + */ +PIXI.BaseTexture.prototype.destroy = function() +{ + if(this.source instanceof Image) + { + this.source.src = null; + } + this.source = null; + PIXI.texturesToDestroy.push(this); +} + +/** + * Helper function that returns a base texture based on an image url + * If the image is not in the base texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @return BaseTexture + */ +PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) +{ + var baseTexture = PIXI.BaseTextureCache[imageUrl]; + if(!baseTexture) + { + // new Image() breaks tex loading in some versions of Chrome. + // See https://code.google.com/p/chromium/issues/detail?id=238071 + var image = new Image();//document.createElement('img'); + if (crossorigin) + { + image.crossOrigin = ''; + } + image.src = imageUrl; + baseTexture = new PIXI.BaseTexture(image); + PIXI.BaseTextureCache[imageUrl] = baseTexture; + } + + return baseTexture; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.TextureCache = {}; +PIXI.FrameCache = {}; + +/** + * A texture stores the information that represents an image or part of an image. It cannot be added + * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used + * + * @class Texture + * @uses EventTarget + * @constructor + * @param baseTexture {BaseTexture} The base texture source to create the texture from + * @param frame {Rectangle} The rectangle frame of the texture to show + */ +PIXI.Texture = function(baseTexture, frame) +{ + PIXI.EventTarget.call( this ); + + if(!frame) + { + this.noFrame = true; + frame = new PIXI.Rectangle(0,0,1,1); + } + + if(baseTexture instanceof PIXI.Texture) + baseTexture = baseTexture.baseTexture; + + /** + * The base texture of this texture + * + * @property baseTexture + * @type BaseTexture + */ + this.baseTexture = baseTexture; + + /** + * The frame specifies the region of the base texture that this texture uses + * + * @property frame + * @type Rectangle + */ + this.frame = frame; + + /** + * The trim point + * + * @property trim + * @type Point + */ + this.trim = new PIXI.Point(); + + this.scope = this; + + if(baseTexture.hasLoaded) + { + if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + //console.log(frame) + + this.setFrame(frame); + } + else + { + var scope = this; + baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); + } +} + +PIXI.Texture.prototype.constructor = PIXI.Texture; + +/** + * Called when the base texture is loaded + * + * @method onBaseTextureLoaded + * @param event + * @private + */ +PIXI.Texture.prototype.onBaseTextureLoaded = function(event) +{ + var baseTexture = this.baseTexture; + baseTexture.removeEventListener( 'loaded', this.onLoaded ); + + if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + this.noFrame = false; + this.width = this.frame.width; + this.height = this.frame.height; + + this.scope.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Destroys this texture + * + * @method destroy + * @param destroyBase {Boolean} Whether to destroy the base texture as well + */ +PIXI.Texture.prototype.destroy = function(destroyBase) +{ + if(destroyBase)this.baseTexture.destroy(); +} + +/** + * Specifies the rectangle region of the baseTexture + * + * @method setFrame + * @param frame {Rectangle} The frame of the texture to set it to + */ +PIXI.Texture.prototype.setFrame = function(frame) +{ + this.frame = frame; + this.width = frame.width; + this.height = frame.height; + + 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); + } + + this.updateFrame = true; + + PIXI.Texture.frameUpdates.push(this); + //this.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Helper function that returns a texture based on an image url + * If the image is not in the texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + * @return Texture + */ +PIXI.Texture.fromImage = function(imageUrl, crossorigin) +{ + var texture = PIXI.TextureCache[imageUrl]; + + if(!texture) + { + texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); + PIXI.TextureCache[imageUrl] = texture; + } + + return texture; +} + +/** + * Helper function that returns a texture based on a frame id + * If the frame id is not in the texture cache an error will be thrown + * + * @static + * @method fromFrame + * @param frameId {String} The frame id of the texture + * @return Texture + */ +PIXI.Texture.fromFrame = function(frameId) +{ + var texture = PIXI.TextureCache[frameId]; + if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); + return texture; +} + +/** + * Helper function that returns a texture based on a canvas element + * If the canvas is not in the texture cache it will be created and loaded + * + * @static + * @method fromCanvas + * @param canvas {Canvas} The canvas element source of the texture + * @return Texture + */ +PIXI.Texture.fromCanvas = function(canvas) +{ + var baseTexture = new PIXI.BaseTexture(canvas); + return new PIXI.Texture(baseTexture); +} + + +/** + * Adds a texture to the textureCache. + * + * @static + * @method addTextureToCache + * @param texture {Texture} + * @param id {String} the id that the texture will be stored against. + */ +PIXI.Texture.addTextureToCache = function(texture, id) +{ + PIXI.TextureCache[id] = texture; +} + +/** + * Remove a texture from the textureCache. + * + * @static + * @method removeTextureFromCache + * @param id {String} the id of the texture to be removed + * @return {Texture} the texture that was removed + */ +PIXI.Texture.removeTextureFromCache = function(id) +{ + var texture = PIXI.TextureCache[id] + PIXI.TextureCache[id] = null; + return texture; +} + +// this is more for webGL.. it contains updated frames.. +PIXI.Texture.frameUpdates = []; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. + + __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. + Otherwise black rectangles will be drawn instead. + + RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: + + var renderTexture = new PIXI.RenderTexture(800, 600); + var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); + sprite.position.x = 800/2; + sprite.position.y = 600/2; + sprite.anchor.x = 0.5; + sprite.anchor.y = 0.5; + renderTexture.render(sprite); + + Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: + + var doc = new PIXI.DisplayObjectContainer(); + doc.addChild(sprite); + renderTexture.render(doc); // Renders to center of renderTexture + + @class RenderTexture + @extends Texture + @constructor + @param width {Number} The width of the render texture + @param height {Number} The height of the render texture + */ +PIXI.RenderTexture = function(width, height) +{ + PIXI.EventTarget.call( this ); + + this.width = width || 100; + this.height = height || 100; + + this.indetityMatrix = PIXI.mat3.create(); + + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + if(PIXI.gl) + { + this.initWebGL(); + } + else + { + this.initCanvas(); + } +} + +PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); +PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; + +/** + * Initializes the webgl data for this texture + * + * @method initWebGL + * @private + */ +PIXI.RenderTexture.prototype.initWebGL = function() +{ + var gl = PIXI.gl; + this.glFramebuffer = gl.createFramebuffer(); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + this.glFramebuffer.width = this.width; + this.glFramebuffer.height = this.height; + + this.baseTexture = new PIXI.BaseTexture(); + + this.baseTexture.width = this.width; + this.baseTexture.height = this.height; + + this.baseTexture._glTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + this.baseTexture.isRender = true; + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); + + // create a projection matrix.. + this.projection = new PIXI.Point(this.width/2 , -this.height/2); + + // set the correct render function.. + this.render = this.renderWebGL; +} + + +PIXI.RenderTexture.prototype.resize = function(width, height) +{ + + this.width = width; + this.height = height; + + if(PIXI.gl) + { + this.projection.x = this.width/2 + this.projection.y = -this.height/2; + + var gl = PIXI.gl; + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + else + { + + this.frame.width = this.width + this.frame.height = this.height; + this.renderer.resize(this.width, this.height); + } +} + +/** + * Initializes the canvas data for this texture + * + * @method initCanvas + * @private + */ +PIXI.RenderTexture.prototype.initCanvas = function() +{ + this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); + + this.baseTexture = new PIXI.BaseTexture(this.renderer.view); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + this.render = this.renderCanvas; +} + +/** + * This function will draw the display object to the texture. + * + * @method renderWebGL + * @param displayObject {DisplayObject} The display object to render this texture on + * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn + * @private + */ +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +{ + var gl = PIXI.gl; + + // enable the alpha color mask.. + gl.colorMask(true, true, true, true); + + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + if(clear) + { + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + // THIS WILL MESS WITH HIT TESTING! + var children = displayObject.children; + + //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; + displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; + // modify to flip... + displayObject.worldTransform[4] = -1; + displayObject.worldTransform[5] = this.projection.y * -2; + + if(position) + { + displayObject.worldTransform[2] = position.x; + displayObject.worldTransform[5] -= position.y; + } + + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + + for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded + * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported + * sprite sheet data formats only include "JSON" at this time. Supported bitmap font + * data formats include "xml" and "fnt". + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.AssetLoader = function(assetURLs, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The array of asset URLs that are going to be loaded + * + * @property assetURLs + * @type Array + */ + this.assetURLs = assetURLs; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * Maps file extension to loader types + * + * @property loadersByType + * @type Object + */ + this.loadersByType = { + "jpg": PIXI.ImageLoader, + "jpeg": PIXI.ImageLoader, + "png": PIXI.ImageLoader, + "gif": PIXI.ImageLoader, + "json": PIXI.JsonLoader, + "anim": PIXI.SpineLoader, + "xml": PIXI.BitmapFontLoader, + "fnt": PIXI.BitmapFontLoader + }; + + +}; + +/** + * Fired when an item has loaded + * @event onProgress + */ + +/** + * Fired when all the assets have loaded + * @event onComplete + */ + +// constructor +PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; + +/** + * Starts loading the assets sequentially + * + * @method load + */ +PIXI.AssetLoader.prototype.load = function() +{ + var scope = this; + + this.loadCount = this.assetURLs.length; + + for (var i=0; i < this.assetURLs.length; i++) + { + var fileName = this.assetURLs[i]; + var fileType = fileName.split("?").shift().split(".").pop().toLowerCase(); + + var loaderClass = this.loadersByType[fileType]; + if(!loaderClass) + throw new Error(fileType + " is an unsupported file type"); + + var loader = new loaderClass(fileName, this.crossorigin); + + loader.addEventListener("loaded", function() + { + scope.onAssetLoaded(); + }); + loader.load(); + } +}; + +/** + * Invoked after each file is loaded + * + * @method onAssetLoaded + * @private + */ +PIXI.AssetLoader.prototype.onAssetLoaded = function() +{ + this.loadCount--; + this.dispatchEvent({type: "onProgress", content: this}); + if(this.onProgress) this.onProgress(); + + if(this.loadCount == 0) + { + this.dispatchEvent({type: "onComplete", content: this}); + if(this.onComplete) this.onComplete(); + } +}; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The json file loader is used to load in JSON data and parsing it + * When loaded this class will dispatch a "loaded" event + * If load failed this class will dispatch a "error" event + * + * @class JsonLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.JsonLoader = function (url, crossorigin) { + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * [read-only] Whether the data has loaded yet + * + * @property loaded + * @type Boolean + * @readOnly + */ + this.loaded = false; + +}; + +// constructor +PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; + +/** + * Loads the JSON data + * + * @method load + */ +PIXI.JsonLoader.prototype.load = function () { + this.ajaxRequest = new AjaxRequest(); + var scope = this; + this.ajaxRequest.onreadystatechange = function () { + scope.onJSONLoaded(); + }; + + this.ajaxRequest.open("GET", this.url, true); + if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); + this.ajaxRequest.send(null); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.JsonLoader.prototype.onJSONLoaded = function () { + if (this.ajaxRequest.readyState == 4) { + if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { + this.json = JSON.parse(this.ajaxRequest.responseText); + + if(this.json.frames) + { + // sprite sheet + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); + + } + else if(this.json.bones) + { + // spine animation + var spineJsonParser = new spine.SkeletonJson(); + var skeletonData = spineJsonParser.readSkeletonData(this.json); + PIXI.AnimCache[this.url] = skeletonData; + this.onLoaded(); + } + else + { + this.onLoaded(); + } + } + else + { + this.onError(); + } + } +}; + +/** + * Invoke when json file loaded + * + * @method onLoaded + * @private + */ +PIXI.JsonLoader.prototype.onLoaded = function () { + this.loaded = true; + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * Invoke when error occured + * + * @method onError + * @private + */ +PIXI.JsonLoader.prototype.onError = function () { + this.dispatchEvent({ + type: "error", + content: this + }); +}; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The sprite sheet loader is used to load in JSON sprite sheet data + * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format + * There is a free version so thats nice, although the paid version is great value for money. + * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. + * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * This loader will also load the image file that the Spritesheet points to as well as the data. + * When loaded this class will dispatch a "loaded" event + * + * @class SpriteSheetLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the sprite sheet JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ + +PIXI.SpriteSheetLoader = function (url, crossorigin) { + /* + * i use texture packer to load the assets.. + * http://www.codeandweb.com/texturepacker + * make sure to set the format as "JSON" + */ + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = null; + + /** + * The frames of the sprite sheet + * + * @property frames + * @type Object + */ + this.frames = {}; +}; + +// constructor +PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; + +/** + * This will begin loading the JSON file + * + * @method load + */ +PIXI.SpriteSheetLoader.prototype.load = function () { + var scope = this; + var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); + jsonLoader.addEventListener("loaded", function (event) { + scope.json = event.content.json; + scope.onJSONLoaded(); + }); + jsonLoader.load(); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); +}; +/** + * Invoke when all files are loaded (json and texture) + * + * @method onLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onLoaded = function () { + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") + * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * When loaded this class will dispatch a 'loaded' event + * + * @class ImageLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the image + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.ImageLoader = function(url, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = PIXI.Texture.fromImage(url, crossorigin); + + /** + * if the image is loaded with loadFramedSpriteSheet + * frames will contain the sprite sheet frames + * + */ + this.frames = []; +}; + +// constructor +PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; + +/** + * Loads image or takes it from cache + * + * @method load + */ +PIXI.ImageLoader.prototype.load = function() +{ + if(!this.texture.baseTexture.hasLoaded) + { + var scope = this; + this.texture.baseTexture.addEventListener("loaded", function() + { + scope.onLoaded(); + }); + } + else + { + this.onLoaded(); + } +}; + +/** + * Invoked when image file is loaded or it is already cached and ready to use + * + * @method onLoaded + * @private + */ +PIXI.ImageLoader.prototype.onLoaded = function() +{ + this.dispatchEvent({type: "loaded", content: this}); +}; + +/** + * Loads image and split it to uniform sized frames + * + * + * @method loadFramedSpriteSheet + * @param frameWidth {Number} with of each frame + * @param frameHeight {Number} height of each frame + * @param textureName {String} if given, the frames will be cached in - format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y>16)/255,(255&a>>8)/255,(255&a)/255]}function d(a){return[(255&a>>16)/255,(255&a>>8)/255,(255&a)/255]}var e=this,f=f||{};f.Point=function(a,b){this.x=a||0,this.y=b||0},f.Point.prototype.clone=function(){return new f.Point(this.x,this.y)},f.Point.prototype.constructor=f.Point,f.Rectangle=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Rectangle.prototype.clone=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Rectangle.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=this.x;if(a>=c&&a<=c+this.width){var d=this.y;if(b>=d&&b<=d+this.height)return!0}return!1},f.Rectangle.prototype.constructor=f.Rectangle,f.Polygon=function(a){if(a instanceof Array||(a=Array.prototype.slice.call(arguments)),"number"==typeof a[0]){for(var b=[],c=0,d=a.length;d>c;c+=2)b.push(new f.Point(a[c],a[c+1]));a=b}this.points=a},f.Polygon.prototype.clone=function(){for(var a=[],b=0;bb!=i>b&&(h-f)*(b-g)/(i-g)+f>a;j&&(c=!c)}return c},f.Polygon.prototype.constructor=f.Polygon,f.Circle=function(a,b,c){this.x=a||0,this.y=b||0,this.radius=c||0},f.Circle.prototype.clone=function(){return new f.Circle(this.x,this.y,this.radius)},f.Circle.prototype.contains=function(a,b){if(this.radius<=0)return!1;var c=this.x-a,d=this.y-b,e=this.radius*this.radius;return c*=c,d*=d,e>=c+d},f.Circle.prototype.constructor=f.Circle,f.Ellipse=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Ellipse.prototype.clone=function(){return new f.Ellipse(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=(a-this.x)/this.width-.5,d=(b-this.y)/this.height-.5;return c*=c,d*=d,.25>c+d},f.Ellipse.getBounds=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.constructor=f.Ellipse,c(),f.mat3={},f.mat3.create=function(){var a=new f.Matrix(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat3.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat4={},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat3.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=m*d+n*g+o*j,c[1]=m*e+n*h+o*k,c[2]=m*f+n*i+o*l,c[3]=p*d+q*g+r*j,c[4]=p*e+q*h+r*k,c[5]=p*f+q*i+r*l,c[6]=s*d+t*g+u*j,c[7]=s*e+t*h+u*k,c[8]=s*f+t*i+u*l,c},f.mat3.clone=function(a){var b=new f.Matrix(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.mat3.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.mat3.toMat4=function(a,b){return b||(b=f.mat4.create()),b[15]=1,b[14]=0,b[13]=0,b[12]=0,b[11]=0,b[10]=a[8],b[9]=a[7],b[8]=a[6],b[7]=0,b[6]=a[5],b[5]=a[4],b[4]=a[3],b[3]=0,b[2]=a[2],b[1]=a[1],b[0]=a[0],b},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat4.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},f.mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,t=b[4],u=b[5],v=b[6],w=b[7],c[4]=t*d+u*h+v*l+w*p,c[5]=t*e+u*i+v*m+w*q,c[6]=t*f+u*j+v*n+w*r,c[7]=t*g+u*k+v*o+w*s,t=b[8],u=b[9],v=b[10],w=b[11],c[8]=t*d+u*h+v*l+w*p,c[9]=t*e+u*i+v*m+w*q,c[10]=t*f+u*j+v*n+w*r,c[11]=t*g+u*k+v*o+w*s,t=b[12],u=b[13],v=b[14],w=b[15],c[12]=t*d+u*h+v*l+w*p,c[13]=t*e+u*i+v*m+w*q,c[14]=t*f+u*j+v*n+w*r,c[15]=t*g+u*k+v*o+w*s,c},f.DisplayObject=function(){this.last=this,this.first=this,this.position=new f.Point,this.scale=new f.Point(1,1),this.pivot=new f.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.parent=null,this.stage=null,this.worldAlpha=1,this._interactive=!1,this.worldTransform=f.mat3.create(),this.localTransform=f.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1,this.filterArea=new f.Rectangle(0,0,1,1)},f.DisplayObject.prototype.constructor=f.DisplayObject,f.DisplayObject.prototype.setInteractive=function(a){this.interactive=a},Object.defineProperty(f.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(a){this._interactive=a,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(f.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(a){a?this._mask?(a.start=this._mask.start,a.end=this._mask.end):(this.addFilter(a),a.renderable=!1):(this.removeFilter(this._mask),this._mask.renderable=!0),this._mask=a}}),Object.defineProperty(f.DisplayObject.prototype,"filters",{get:function(){return this._filters},set:function(a){if(a){this._filters&&this.removeFilter(this._filters),this.addFilter(a);for(var b=[],c=0;c=0&&b<=this.children.length))throw new Error(a+" The index "+b+" supplied is out of bounds "+this.children.length);if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.stage){var c=a;do c.interactive&&(this.stage.dirty=!0),c.stage=this.stage,c=c._iNext;while(c)}var d,e,f=a.first,g=a.last;if(b==this.children.length){e=this.last;for(var h=this,i=this.last;h;)h.last==i&&(h.last=a.last),h=h.parent}else e=0==b?this:this.children[b-1].last;d=e._iNext,d&&(d._iPrev=g,g._iNext=d),f._iPrev=e,e._iNext=f,this.children.splice(b,0,a),this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.swapChildren=function(){},f.DisplayObjectContainer.prototype.getChildAt=function(a){if(a>=0&&aa;a++)this.children[a].updateTransform()}},f.blendModes={},f.blendModes.NORMAL=0,f.blendModes.SCREEN=1,f.Sprite=function(a){f.DisplayObjectContainer.call(this),this.anchor=new f.Point,this.texture=a,this.blendMode=f.blendModes.NORMAL,this._width=0,this._height=0,a.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Sprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Sprite.prototype.constructor=f.Sprite,Object.defineProperty(f.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(a){this.scale.x=a/this.texture.frame.width,this._width=a}}),Object.defineProperty(f.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(a){this.scale.y=a/this.texture.frame.height,this._height=a}}),f.Sprite.prototype.setTexture=function(a){this.texture.baseTexture!=a.baseTexture?(this.textureChange=!0,this.texture=a,this.__renderGroup&&this.__renderGroup.updateTexture(this)):this.texture=a,this.updateFrame=!0},f.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},f.Sprite.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache"+this);return new f.Sprite(b)},f.Sprite.fromImage=function(a){var b=f.Texture.fromImage(a);return new f.Sprite(b)},f.MovieClip=function(a){f.Sprite.call(this,a[0]),this.textures=a,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},f.MovieClip.prototype=Object.create(f.Sprite.prototype),f.MovieClip.prototype.constructor=f.MovieClip,Object.defineProperty(f.MovieClip.prototype,"totalFrames",{get:function(){return this.textures.length}}),f.MovieClip.prototype.stop=function(){this.playing=!1},f.MovieClip.prototype.play=function(){this.playing=!0},f.MovieClip.prototype.gotoAndStop=function(a){this.playing=!1,this.currentFrame=a;var b=0|this.currentFrame+.5;this.setTexture(this.textures[b%this.textures.length])},f.MovieClip.prototype.gotoAndPlay=function(a){this.currentFrame=a,this.playing=!0},f.MovieClip.prototype.updateTransform=function(){if(f.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var a=0|this.currentFrame+.5;this.loop||a=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},f.FilterBlock=function(){this.visible=!0,this.renderable=!0},f.Text=function(a,b){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),f.Sprite.call(this,f.Texture.fromCanvas(this.canvas)),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.Text.prototype=Object.create(f.Sprite.prototype),f.Text.prototype.constructor=f.Text,f.Text.prototype.setStyle=function(a){a=a||{},a.font=a.font||"bold 20pt Arial",a.fill=a.fill||"black",a.align=a.align||"left",a.stroke=a.stroke||"black",a.strokeThickness=a.strokeThickness||0,a.wordWrap=a.wordWrap||!1,a.wordWrapWidth=a.wordWrapWidth||100,this.style=a,this.dirty=!0},f.Text.prototype.setText=function(a){this.text=a.toString()||" ",this.dirty=!0},f.Text.prototype.updateText=function(){this.context.font=this.style.font;var a=this.text;this.style.wordWrap&&(a=this.wordWrap(this.text));for(var b=a.split(/(?:\r\n|\r|\n)/),c=[],d=0,e=0;ee?(g>0&&(b+="\n"),b+=f[g]+" ",e=this.style.wordWrapWidth-h):(e-=i,b+=f[g]+" ")}b+="\n"}return b},f.Text.prototype.destroy=function(a){a&&this.texture.destroy()},f.Text.heightCache={},f.BitmapText=function(a,b){f.DisplayObjectContainer.call(this),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.BitmapText.prototype=Object.create(f.DisplayObjectContainer.prototype),f.BitmapText.prototype.constructor=f.BitmapText,f.BitmapText.prototype.setText=function(a){this.text=a||" ",this.dirty=!0},f.BitmapText.prototype.setStyle=function(a){a=a||{},a.align=a.align||"left",this.style=a;var b=a.font.split(" ");this.fontName=b[b.length-1],this.fontSize=b.length>=2?parseInt(b[b.length-2],10):f.BitmapText.fonts[this.fontName].size,this.dirty=!0},f.BitmapText.prototype.updateText=function(){for(var a=f.BitmapText.fonts[this.fontName],b=new f.Point,c=null,d=[],e=0,g=[],h=0,i=this.fontSize/a.size,j=0;j=j;j++){var n=0;"right"==this.style.align?n=e-g[j]:"center"==this.style.align&&(n=(e-g[j])/2),m.push(n)}for(j=0;j0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.BitmapText.fonts={},f.InteractionManager=function(a){this.stage=a,this.mouse=new f.InteractionData,this.touchs={},this.tempPoint=new f.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0},f.InteractionManager.prototype.constructor=f.InteractionManager,f.InteractionManager.prototype.collectInteractiveSprite=function(a,b){for(var c=a.children,d=c.length,e=d-1;e>=0;e--){var f=c[e];f.interactive?(b.interactiveChildren=!0,this.interactiveItems.push(f),f.children.length>0&&this.collectInteractiveSprite(f,f)):(f.__iParent=null,f.children.length>0&&this.collectInteractiveSprite(f,b))}},f.InteractionManager.prototype.setTarget=function(a){this.target=a,null===this.interactionDOMElement&&this.setTargetDomElement(a.view),document.body.addEventListener("mouseup",this.onMouseUp,!0)},f.InteractionManager.prototype.setTargetDomElement=function(a){null!==this.interactionDOMElement&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]="",this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0)),window.navigator.msPointerEnabled&&(a.style["-ms-content-zooming"]="none",a.style["-ms-touch-action"]="none"),this.interactionDOMElement=a,a.addEventListener("mousemove",this.onMouseMove,!0),a.addEventListener("mousedown",this.onMouseDown,!0),a.addEventListener("mouseout",this.onMouseOut,!0),a.addEventListener("touchstart",this.onTouchStart,!0),a.addEventListener("touchend",this.onTouchEnd,!0),a.addEventListener("touchmove",this.onTouchMove,!0)},f.InteractionManager.prototype.update=function(){if(this.target){var a=Date.now(),b=a-this.last;if(b=30*b/1e3,!(1>b)){if(this.last=a,this.dirty){this.dirty=!1;for(var c=this.interactiveItems.length,d=0;c>d;d++)this.interactiveItems[d].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var e=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var d=0;e>d;d++){var f=this.interactiveItems[d];(f.mouseover||f.mouseout||f.buttonMode)&&(f.__hit=this.hitTest(f,this.mouse),this.mouse.target=f,f.__hit?(f.buttonMode&&(this.interactionDOMElement.style.cursor="pointer"),f.__isOver||(f.mouseover&&f.mouseover(this.mouse),f.__isOver=!0)):f.__isOver&&(f.mouseout&&f.mouseout(this.mouse),f.__isOver=!1))}}}},f.InteractionManager.prototype.onMouseMove=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(a.clientX-b.left)*(this.target.width/b.width),this.mouse.global.y=(a.clientY-b.top)*(this.target.height/b.height);var c=this.interactiveItems.length;this.mouse.global;for(var d=0;c>d;d++){var e=this.interactiveItems[d];e.mousemove&&e.mousemove(this.mouse)}},f.InteractionManager.prototype.onMouseDown=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactiveItems.length;this.mouse.global,this.stage;for(var c=0;b>c;c++){var d=this.interactiveItems[c];if((d.mousedown||d.click)&&(d.__mouseIsDown=!0,d.__hit=this.hitTest(d,this.mouse),d.__hit&&(d.mousedown&&d.mousedown(this.mouse),d.__isDown=!0,!d.interactiveChildren)))break}},f.InteractionManager.prototype.onMouseOut=function(){var a=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var b=0;a>b;b++){var c=this.interactiveItems[b];c.__isOver&&(this.mouse.target=c,c.mouseout&&c.mouseout(this.mouse),c.__isOver=!1)}},f.InteractionManager.prototype.onMouseUp=function(a){this.mouse.originalEvent=a||window.event,this.mouse.global;for(var b=this.interactiveItems.length,c=!1,d=0;b>d;d++){var e=this.interactiveItems[d];(e.mouseup||e.mouseupoutside||e.click)&&(e.__hit=this.hitTest(e,this.mouse),e.__hit&&!c?(e.mouseup&&e.mouseup(this.mouse),e.__isDown&&e.click&&e.click(this.mouse),e.interactiveChildren||(c=!0)):e.__isDown&&e.mouseupoutside&&e.mouseupoutside(this.mouse),e.__isDown=!1)}},f.InteractionManager.prototype.hitTest=function(a,b){var c=b.global;if(a.vcount!==f.visibleCount)return!1;var d=a instanceof f.Sprite,e=a.worldTransform,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=1/(g*k+h*-j),n=k*m*c.x+-h*m*c.y+(l*h-i*k)*m,o=g*m*c.y+-j*m*c.x+(-l*g+i*j)*m;if(b.target=a,a.hitArea&&a.hitArea.contains)return a.hitArea.contains(n,o)?(b.target=a,!0):!1;if(d){var p,q=a.texture.frame.width,r=a.texture.frame.height,s=-q*a.anchor.x;if(n>s&&s+q>n&&(p=-r*a.anchor.y,o>p&&p+r>o))return b.target=a,!0}for(var t=a.children.length,u=0;t>u;u++){var v=a.children[u],w=this.hitTest(v,b);if(w)return b.target=a,!0}return!1},f.InteractionManager.prototype.onTouchMove=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;dd;d++){var h=this.interactiveItems[d];h.touchmove&&h.touchmove(f)}},f.InteractionManager.prototype.onTouchStart=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i];if((j.touchstart||j.tap)&&(j.__hit=this.hitTest(j,g),j.__hit&&(j.touchstart&&j.touchstart(g),j.__isDown=!0,j.__touchData=g,!j.interactiveChildren)))break}}},f.InteractionManager.prototype.onTouchEnd=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i],k=j.__touchData;j.__hit=this.hitTest(j,f),k==f&&(f.originalEvent=a||window.event,(j.touchend||j.tap)&&(j.__hit&&!g?(j.touchend&&j.touchend(f),j.__isDown&&j.tap&&j.tap(f),j.interactiveChildren||(g=!0)):j.__isDown&&j.touchendoutside&&j.touchendoutside(f),j.__isDown=!1),j.__touchData=null)}this.pool.push(f),this.touchs[e.identifier]=null}},f.InteractionData=function(){this.global=new f.Point,this.local=new f.Point,this.target,this.originalEvent},f.InteractionData.prototype.getLocalPosition=function(a){var b=a.worldTransform,c=this.global,d=b[0],e=b[1],g=b[2],h=b[3],i=b[4],j=b[5],k=1/(d*i+e*-h);return new f.Point(i*k*c.x+-e*k*c.y+(j*e-g*i)*k,d*k*c.y+-h*k*c.x+(-j*d+g*h)*k)},f.InteractionData.prototype.constructor=f.InteractionData,f.Stage=function(a){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=!0,this.interactionManager=new f.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new f.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(a),this.worldVisible=!0},f.Stage.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Stage.prototype.constructor=f.Stage,f.Stage.prototype.setInteractionDelegate=function(a){this.interactionManager.setTargetDomElement(a)},f.Stage.prototype.updateTransform=function(){this.worldAlpha=1,this.vcount=f.visibleCount;for(var a=0,b=this.children.length;b>a;a++)this.children[a].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},f.Stage.prototype.setBackgroundColor=function(a){this.backgroundColor=a||0,this.backgroundColorSplit=d(this.backgroundColor);var b=this.backgroundColor.toString(16);b="000000".substr(0,6-b.length)+b,this.backgroundColorString="#"+b},f.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var h=0,i=["ms","moz","webkit","o"],j=0;j>>>>>>>>"),console.log("_");var b=0,c=a.first;for(console.log(c);c._iNext;)if(b++,c=c._iNext,console.log(c),b>100){console.log("BREAK");break}},f.EventTarget=function(){var a={};this.addEventListener=this.on=function(b,c){void 0===a[b]&&(a[b]=[]),-1===a[b].indexOf(c)&&a[b].push(c)},this.dispatchEvent=this.emit=function(b){if(a[b.type]&&a[b.type].length)for(var c=0,d=a[b.type].length;d>c;c++)a[b.type][c](b)},this.removeEventListener=this.off=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}},f.autoDetectRenderer=function(a,b,c,d,e){a||(a=800),b||(b=600);var g=function(){try{var a=document.createElement("canvas");return!!window.WebGLRenderingContext&&(a.getContext("webgl")||a.getContext("experimental-webgl"))}catch(b){return!1}}();if(g){var h=-1!=navigator.userAgent.toLowerCase().indexOf("msie");g=!h}return g?new f.WebGLRenderer(a,b,c,d,e):new f.CanvasRenderer(a,b,c,d)},f.PolyK={},f.PolyK.Triangulate=function(a){var b=!0,c=a.length>>1;if(3>c)return[];for(var d=[],e=[],g=0;c>g;g++)e.push(g);for(var g=0,h=c;h>3;){var i=e[(g+0)%h],j=e[(g+1)%h],k=e[(g+2)%h],l=a[2*i],m=a[2*i+1],n=a[2*j],o=a[2*j+1],p=a[2*k],q=a[2*k+1],r=!1;if(f.PolyK._convex(l,m,n,o,p,q,b)){r=!0;for(var s=0;h>s;s++){var t=e[s];if(t!=i&&t!=j&&t!=k&&f.PolyK._PointInTriangle(a[2*t],a[2*t+1],l,m,n,o,p,q)){r=!1;break}}}if(r)d.push(i,j,k),e.splice((g+1)%h,1),h--,g=0;else if(g++>3*h){if(!b)return console.log("PIXI Warning: shape too complex to fill"),[];var d=[];e=[];for(var g=0;c>g;g++)e.push(g);g=0,h=c,b=!1}}return d.push(e[0],e[1],e[2]),d},f.PolyK._PointInTriangle=function(a,b,c,d,e,f,g,h){var i=g-c,j=h-d,k=e-c,l=f-d,m=a-c,n=b-d,o=i*i+j*j,p=i*k+j*l,q=i*m+j*n,r=k*k+l*l,s=k*m+l*n,t=1/(o*r-p*p),u=(r*q-p*s)*t,v=(o*s-p*q)*t;return u>=0&&v>=0&&1>u+v},f.PolyK._convex=function(a,b,c,d,e,f,g){return(b-d)*(e-c)+(c-a)*(f-d)>=0==g},f.initDefaultShaders=function(){f.primitiveShader=new f.PrimitiveShader,f.primitiveShader.init(),f.stripShader=new f.StripShader,f.stripShader.init(),f.defaultShader=new f.PixiShader,f.defaultShader.init();var a=f.gl,b=f.defaultShader.program;a.useProgram(b),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.primitiveShader.program),a.disableVertexAttribArray(f.defaultShader.aVertexPosition),a.disableVertexAttribArray(f.defaultShader.colorAttribute),a.disableVertexAttribArray(f.defaultShader.aTextureCoord),a.enableVertexAttribArray(f.primitiveShader.aVertexPosition),a.enableVertexAttribArray(f.primitiveShader.colorAttribute)},f.deactivatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program),a.disableVertexAttribArray(f.primitiveShader.aVertexPosition),a.disableVertexAttribArray(f.primitiveShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activateStripShader=function(){var a=f.gl;a.useProgram(f.stripShader.program)},f.deactivateStripShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program)},f.CompileVertexShader=function(a,b){return f._CompileShader(a,b,a.VERTEX_SHADER)},f.CompileFragmentShader=function(a,b){return f._CompileShader(a,b,a.FRAGMENT_SHADER)},f._CompileShader=function(a,b,c){var d=b.join("\n"),e=a.createShader(c);return a.shaderSource(e,d),a.compileShader(e),a.getShaderParameter(e,a.COMPILE_STATUS)?e:(console.log(a.getShaderInfoLog(e)),null)},f.compileProgram=function(a,b){var c=f.gl,d=f.CompileFragmentShader(c,b),e=f.CompileVertexShader(c,a),g=c.createProgram();return c.attachShader(g,e),c.attachShader(g,d),c.linkProgram(g),c.getProgramParameter(g,c.LINK_STATUS)||console.log("Could not initialise shaders"),g},f.PixiShader=function(){this.program,this.fragmentSrc=["precision lowp float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;","}"]},f.PixiShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc||f.PixiShader.defaultVertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"); -for(var c in this.uniforms)this.uniforms[c].uniformLocation=b.getUniformLocation(a,c);this.program=a},f.PixiShader.prototype.syncUniforms=function(){var a=f.gl;for(var b in this.uniforms){var c=this.uniforms[b].type;if("f"==c&&a.uniform1f(this.uniforms[b].uniformLocation,this.uniforms[b].value),"f2"==c)a.uniform2f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("f4"==c)a.uniform4fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("mat4"==c)a.uniformMatrix4fv(this.uniforms[b].uniformLocation,!1,this.uniforms[b].value);else if("sampler2D"==c){var d=this.uniforms[b].value;a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,d.baseTexture._glTexture),a.uniform1i(this.uniforms[b].uniformLocation,1)}}},f.PixiShader.defaultVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","varying vec2 vTextureCoord;","varying float vColor;","const vec2 center = vec2(-1.0, 1.0);","void main(void) {","gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.StripShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying vec2 offsetVector;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"]},f.StripShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.PrimitiveShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"]},f.PrimitiveShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.WebGLGraphics=function(){},f.WebGLGraphics.renderGraphics=function(a,b){var c=f.gl;a._webGL||(a._webGL={points:[],indices:[],lastIndex:0,buffer:c.createBuffer(),indexBuffer:c.createBuffer()}),a.dirty&&(a.dirty=!1,a.clearDirty&&(a.clearDirty=!1,a._webGL.lastIndex=0,a._webGL.points=[],a._webGL.indices=[]),f.WebGLGraphics.updateGraphics(a)),f.activatePrimitiveShader();var d=f.mat3.clone(a.worldTransform);f.mat3.transpose(d),c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA),c.uniformMatrix3fv(f.primitiveShader.translationMatrix,!1,d),c.uniform2f(f.primitiveShader.projectionVector,b.x,-b.y),c.uniform2f(f.primitiveShader.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(f.primitiveShader.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.primitiveShader.aVertexPosition,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveShader.colorAttribute,4,c.FLOAT,!1,24,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),c.drawElements(c.TRIANGLE_STRIP,a._webGL.indices.length,c.UNSIGNED_SHORT,0),f.deactivatePrimitiveShader()},f.WebGLGraphics.updateGraphics=function(a){for(var b=a._webGL.lastIndex;b3&&f.WebGLGraphics.buildPoly(c,a._webGL),c.lineWidth>0&&f.WebGLGraphics.buildLine(c,a._webGL)):c.type==f.Graphics.RECT?f.WebGLGraphics.buildRectangle(c,a._webGL):(c.type==f.Graphics.CIRC||c.type==f.Graphics.ELIP)&&f.WebGLGraphics.buildCircle(c,a._webGL)}a._webGL.lastIndex=a.graphicsData.length;var d=f.gl;a._webGL.glPoints=new Float32Array(a._webGL.points),d.bindBuffer(d.ARRAY_BUFFER,a._webGL.buffer),d.bufferData(d.ARRAY_BUFFER,a._webGL.glPoints,d.STATIC_DRAW),a._webGL.glIndicies=new Uint16Array(a._webGL.indices),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),d.bufferData(d.ELEMENT_ARRAY_BUFFER,a._webGL.glIndicies,d.STATIC_DRAW)},f.WebGLGraphics.buildRectangle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3];if(a.fill){var j=d(a.fillColor),k=a.fillAlpha,l=j[0]*k,m=j[1]*k,n=j[2]*k,o=b.points,p=b.indices,q=o.length/6;o.push(e,g),o.push(l,m,n,k),o.push(e+h,g),o.push(l,m,n,k),o.push(e,g+i),o.push(l,m,n,k),o.push(e+h,g+i),o.push(l,m,n,k),p.push(q,q,q+1,q+2,q+3,q+3)}a.lineWidth&&(a.points=[e,g,e+h,g,e+h,g+i,e,g+i,e,g],f.WebGLGraphics.buildLine(a,b))},f.WebGLGraphics.buildCircle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3],j=40,k=2*Math.PI/j;if(a.fill){var l=d(a.fillColor),m=a.fillAlpha,n=l[0]*m,o=l[1]*m,p=l[2]*m,q=b.points,r=b.indices,s=q.length/6;r.push(s);for(var t=0;j+1>t;t++)q.push(e,g,n,o,p,m),q.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i,n,o,p,m),r.push(s++,s++);r.push(s-1)}if(a.lineWidth){a.points=[];for(var t=0;j+1>t;t++)a.points.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i);f.WebGLGraphics.buildLine(a,b)}},f.WebGLGraphics.buildLine=function(a,b){var c=a.points;if(0!=c.length){if(a.lineWidth%2)for(var e=0;ee;e++)k=c[2*(e-1)],l=c[2*(e-1)+1],m=c[2*e],n=c[2*e+1],o=c[2*(e+1)],p=c[2*(e+1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,s=-(n-p),t=m-o,E=Math.sqrt(s*s+t*t),s/=E,t/=E,s*=K,t*=K,w=-r+l-(-r+n),x=-q+m-(-q+k),y=(-q+k)*(-r+n)-(-q+m)*(-r+l),z=-t+p-(-t+n),A=-s+m-(-s+o),B=(-s+o)*(-t+n)-(-s+m)*(-t+p),C=w*A-z*x,Math.abs(C)<.1?(C+=10.1,F.push(m-q,n-r,N,O,P,M),F.push(m+q,n+r,N,O,P,M)):(px=(x*B-A*y)/C,py=(z*y-w*B)/C,D=(px-m)*(px-m)+(py-n)+(py-n),D>19600?(u=q-s,v=r-t,E=Math.sqrt(u*u+v*v),u/=E,v/=E,u*=K,v*=K,F.push(m-u,n-v),F.push(N,O,P,M),F.push(m+u,n+v),F.push(N,O,P,M),F.push(m-u,n-v),F.push(N,O,P,M),I++):(F.push(px,py),F.push(N,O,P,M),F.push(m-(px-m),n-(py-n)),F.push(N,O,P,M)));k=c[2*(H-2)],l=c[2*(H-2)+1],m=c[2*(H-1)],n=c[2*(H-1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,F.push(m-q,n-r),F.push(N,O,P,M),F.push(m+q,n+r),F.push(N,O,P,M),G.push(J);for(var e=0;I>e;e++)G.push(J++);G.push(J-1)}},f.WebGLGraphics.buildPoly=function(a,b){var c=a.points;if(!(c.length<6)){for(var e=b.points,g=b.indices,h=c.length/2,i=d(a.fillColor),j=a.fillAlpha,k=i[0]*j,l=i[1]*j,m=i[2]*j,n=f.PolyK.Triangulate(c),o=e.length/6,p=0;pp;p++)e.push(c[2*p],c[2*p+1],k,l,m,j)}},f._defaultFrame=new f.Rectangle(0,0,1,1),f.gl,f.WebGLRenderer=function(a,b,c,d,e){this.transparent=!!d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var g=this;this.view.addEventListener("webglcontextlost",function(a){g.handleContextLost(a)},!1),this.view.addEventListener("webglcontextrestored",function(a){g.handleContextRestored(a)},!1),this.batchs=[];var h={alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0};try{f.gl=this.gl=this.view.getContext("experimental-webgl",h)}catch(i){try{f.gl=this.gl=this.view.getContext("webgl",h)}catch(i){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}}f.initDefaultShaders();var j=this.gl;j.useProgram(f.defaultShader.program),f.WebGLRenderer.gl=j,this.batch=new f.WebGLBatch(j),j.disable(j.DEPTH_TEST),j.disable(j.CULL_FACE),j.enable(j.BLEND),j.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),f.offset=new f.Point(0,0),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new f.WebGLRenderGroup(this.gl,this.transparent)},f.WebGLRenderer.prototype.constructor=f.WebGLRenderer,f.WebGLRenderer.getBatch=function(){return 0==f._batchs.length?new f.WebGLBatch(f.WebGLRenderer.gl):f._batchs.pop()},f.WebGLRenderer.returnBatch=function(a){a.clean(),f._batchs.push(a)},f.WebGLRenderer.prototype.render=function(a){if(!this.contextLost){this.__stage!==a&&(this.__stage=a,this.stageRenderGroup.setRenderable(a)),f.WebGLRenderer.updateTextures(),f.visibleCount++,a.updateTransform();var b=this.gl;if(b.colorMask(!0,!0,!0,this.transparent),b.viewport(0,0,this.width,this.height),b.bindFramebuffer(b.FRAMEBUFFER,null),b.clearColor(a.backgroundColorSplit[0],a.backgroundColorSplit[1],a.backgroundColorSplit[2],!this.transparent),b.clear(b.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=a.backgroundColorSplit,f.projection.x=this.width/2,f.projection.y=-this.height/2,this.stageRenderGroup.render(f.projection),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0){for(var c=0;cc;c++){var d=6*c,e=4*c;this.indices[d+0]=e+0,this.indices[d+1]=e+1,this.indices[d+2]=e+2,this.indices[d+3]=e+0,this.indices[d+4]=e+2,this.indices[d+5]=e+3}a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,this.indices,a.STATIC_DRAW)},f.WebGLBatch.prototype.refresh=function(){this.gl,this.dynamicSizen;n++)renderable=this.batchs[n],renderable instanceof f.WebGLBatch?this.batchs[n].render():this.renderSpecial(renderable,b);endBatch instanceof f.WebGLBatch?endBatch.render(0,h+1):this.renderSpecial(endBatch,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){var c=a.vcount===f.visibleCount;a instanceof f.TilingSprite?c&&this.renderTilingSprite(a,b):a instanceof f.Strip?c&&this.renderStrip(a,b):a instanceof f.CustomRenderable?c&&a.renderWebGL(this,b):a instanceof f.Graphics?c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b):a instanceof f.FilterBlock&&this.handleFilterBlock(a,b)},flip=!1;var l=[],m=0;f.WebGLRenderGroup.prototype.handleFilterBlock=function(a,b){var c=f.gl;if(a.open)a.data instanceof Array?this.filterManager.pushFilter(a):(m++,l.push(a),c.enable(c.STENCIL_TEST),c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.INCR),f.WebGLGraphics.renderGraphics(a.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP));else if(a.data instanceof Array)this.filterManager.popFilter();else{var d=l.pop(a);d&&(c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.DECR),f.WebGLGraphics.renderGraphics(d.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP)),c.disable(c.STENCIL_TEST)}},f.WebGLRenderGroup.prototype.updateTexture=function(a){this.removeObject(a);for(var b=a.first;b!=this.root&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););this.insertObject(a,b,c)},f.WebGLRenderGroup.prototype.addFilterBlocks=function(a,b){a.__renderGroup=this,b.__renderGroup=this;for(var c=a;c!=this.root.first&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root.first&&(d=d._iPrev,!d.renderable||!d.__renderGroup););this.insertAfter(b,d)},f.WebGLRenderGroup.prototype.removeFilterBlocks=function(a,b){this.removeObject(a),this.removeObject(b)},f.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(a){a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a);for(var b=a.first;b!=this.root.first&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););var d=a.first,e=a.last._iNext;do d.__renderGroup=this,d.renderable&&(this.insertObject(d,b,c),b=d),d=d._iNext;while(d!=e)},f.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(a){if(a.__renderGroup==this){a.last;do a.__renderGroup=null,a.renderable&&this.removeObject(a),a=a._iNext;while(a)}},f.WebGLRenderGroup.prototype.insertObject=function(a,b,c){var d=b,e=c;if(a instanceof f.Sprite){var g,h;if(d instanceof f.Sprite){if(g=d.batch,g&&g.texture==a.texture.baseTexture&&g.blendMode==a.blendMode)return g.insertAfter(a,d),void 0}else g=d;if(e)if(e instanceof f.Sprite){if(h=e.batch){if(h.texture==a.texture.baseTexture&&h.blendMode==a.blendMode)return h.insertBefore(a,e),void 0;if(h==g){var i=g.split(e),j=f.WebGLRenderer.getBatch(),k=this.batchs.indexOf(g);return j.init(a),this.batchs.splice(k+1,0,j,i),void 0}}}else h=e;var j=f.WebGLRenderer.getBatch();if(j.init(a),g){var k=this.batchs.indexOf(g);this.batchs.splice(k+1,0,j)}else this.batchs.push(j)}else a instanceof f.TilingSprite?this.initTilingSprite(a):a instanceof f.Strip&&this.initStrip(a),this.insertAfter(a,d)},f.WebGLRenderGroup.prototype.insertAfter=function(a,b){if(b instanceof f.Sprite){var c=b.batch;if(c)if(c.tail==b){var d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a)}else{var e=c.split(b.__next),d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a,e)}else this.batchs.push(a)}else{var d=this.batchs.indexOf(b);this.batchs.splice(d+1,0,a)}},f.WebGLRenderGroup.prototype.removeObject=function(a){var b;if(a instanceof f.Sprite){var c=a.batch;if(!c)return;c.remove(a),0==c.size&&(b=c)}else b=a;if(b){var d=this.batchs.indexOf(b);if(-1==d)return;if(0==d||d==this.batchs.length-1)return this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),void 0;if(this.batchs[d-1]instanceof f.WebGLBatch&&this.batchs[d+1]instanceof f.WebGLBatch&&this.batchs[d-1].texture==this.batchs[d+1].texture&&this.batchs[d-1].blendMode==this.batchs[d+1].blendMode)return this.batchs[d-1].merge(this.batchs[d+1]),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),f.WebGLRenderer.returnBatch(this.batchs[d+1]),this.batchs.splice(d,2),void 0;this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b)}},f.WebGLRenderGroup.prototype.initTilingSprite=function(a){var b=this.gl;a.verticies=new Float32Array([0,0,a.width,0,a.width,a.height,0,a.height]),a.uvs=new Float32Array([0,0,1,0,1,1,0,1]),a.colors=new Float32Array([1,1,1,1]),a.indices=new Uint16Array([0,1,3,2]),a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW),a.texture.baseTexture._glTexture?(b.bindTexture(b.TEXTURE_2D,a.texture.baseTexture._glTexture),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.REPEAT),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.REPEAT),a.texture.baseTexture._powerOf2=!0):a.texture.baseTexture._powerOf2=!0},f.WebGLRenderGroup.prototype.renderStrip=function(a,b){var c=this.gl;f.activateStripShader();var d=f.stripShader;d.program;var e=f.mat3.clone(a.worldTransform);f.mat3.transpose(e),c.uniformMatrix3fv(d.translationMatrix,!1,e),c.uniform2f(d.projectionVector,b.x,b.y),c.uniform2f(d.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(d.alpha,a.worldAlpha),a.dirty?(a.dirty=!1,c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferData(c.ARRAY_BUFFER,a.verticies,c.STATIC_DRAW),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferData(c.ARRAY_BUFFER,a.uvs,c.STATIC_DRAW),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.bufferData(c.ARRAY_BUFFER,a.colors,c.STATIC_DRAW),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,a.indices,c.STATIC_DRAW)):(c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.verticies),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer)),c.drawElements(c.TRIANGLE_STRIP,a.indices.length,c.UNSIGNED_SHORT,0),f.deactivateStripShader()},f.WebGLRenderGroup.prototype.renderTilingSprite=function(a,b){var c=this.gl;f.shaderProgram;var d=a.tilePosition,e=a.tileScale,g=d.x/a.texture.baseTexture.width,h=d.y/a.texture.baseTexture.height,i=a.width/a.texture.baseTexture.width/e.x,j=a.height/a.texture.baseTexture.height/e.y;a.uvs[0]=0-g,a.uvs[1]=0-h,a.uvs[2]=1*i-g,a.uvs[3]=0-h,a.uvs[4]=1*i-g,a.uvs[5]=1*j-h,a.uvs[6]=0-g,a.uvs[7]=1*j-h,c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.uvs),this.renderStrip(a,b)},f.WebGLRenderGroup.prototype.initStrip=function(a){var b=this.gl;this.shaderProgram,a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW)},f.WebGLFilterManager=function(a){this.transparent=a,this.filterStack=[],this.texturePool=[],this.offsetX=0,this.offsetY=0,this.initShaderBuffers()},f.WebGLFilterManager.prototype.begin=function(a,b){this.width=2*a.x,this.height=2*-a.y,this.buffer=b},f.WebGLFilterManager.prototype.pushFilter=function(a){var b=f.gl;this.filterStack.push(a);var c=a.filterPasses[0];this.offsetX+=a.target.filterArea.x,this.offsetY+=a.target.filterArea.y;var d=this.texturePool.pop();d||(d=new f.FilterTexture(this.width,this.height)),b.bindTexture(b.TEXTURE_2D,d.texture),this.getBounds(a.target);var e=a.target.filterArea,g=c.padding;e.x-=g,e.y-=g,e.width+=2*g,e.height+=2*g,e.x<0&&(e.x=0),e.width>this.width&&(e.width=this.width),e.y<0&&(e.y=0),e.height>this.height&&(e.height=this.height),b.bindFramebuffer(b.FRAMEBUFFER,d.frameBuffer),b.viewport(0,0,e.width,e.height),f.projection.x=e.width/2,f.projection.y=-e.height/2,f.offset.x=-e.x,f.offset.y=-e.y,b.uniform2f(f.defaultShader.projectionVector,e.width/2,-e.height/2),b.uniform2f(f.defaultShader.offsetVector,-e.x,-e.y),b.colorMask(!0,!0,!0,!0),b.clearColor(0,0,0,0),b.clear(b.COLOR_BUFFER_BIT),a._glFilterTexture=d},f.WebGLFilterManager.prototype.popFilter=function(){var a=f.gl,b=this.filterStack.pop(),c=b.target.filterArea,d=b._glFilterTexture;if(b.filterPasses.length>1){a.viewport(0,0,c.width,c.height),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer),this.vertexArray[0]=0,this.vertexArray[1]=c.height,this.vertexArray[2]=c.width,this.vertexArray[3]=c.height,this.vertexArray[4]=0,this.vertexArray[5]=0,this.vertexArray[6]=c.width,this.vertexArray[7]=0,a.bufferSubData(a.ARRAY_BUFFER,0,this.vertexArray),a.bindBuffer(a.ARRAY_BUFFER,this.uvBuffer),this.uvArray[2]=c.width/this.width,this.uvArray[5]=c.height/this.height,this.uvArray[6]=c.width/this.width,this.uvArray[7]=c.height/this.height,a.bufferSubData(a.ARRAY_BUFFER,0,this.uvArray);var e=d,g=this.texturePool.pop();g||(g=new f.FilterTexture(this.width,this.height)),a.bindFramebuffer(a.FRAMEBUFFER,g.frameBuffer),a.clear(a.COLOR_BUFFER_BIT),a.disable(a.BLEND);for(var h=0;hs?s:E,E=E>t?t:E,E=E>u?u:E,E=E>v?v:E,F=F>w?w:F,F=F>x?x:F,F=F>y?y:F,F=F>z?z:F,C=s>C?s:C,C=t>C?t:C,C=u>C?u:C,C=v>C?v:C,D=w>D?w:D,D=x>D?x:D,D=y>D?y:D,D=z>D?z:D),l=!1,A=A._iNext}while(A!=B);a.filterArea.x=E,a.filterArea.y=F,a.filterArea.width=C-E,a.filterArea.height=D-F},f.FilterTexture=function(a,b){var c=f.gl;this.frameBuffer=c.createFramebuffer(),this.texture=c.createTexture(),c.bindTexture(c.TEXTURE_2D,this.texture),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.bindFramebuffer(c.FRAMEBUFFER,this.framebuffer),c.bindFramebuffer(c.FRAMEBUFFER,this.frameBuffer),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,this.texture,0),this.resize(a,b)},f.FilterTexture.prototype.resize=function(a,b){this.width=a,this.height=b;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.texture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,a,b,0,c.RGBA,c.UNSIGNED_BYTE,null)},f.CanvasRenderer=function(a,b,c,d){this.transparent=d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},f.CanvasRenderer.prototype.constructor=f.CanvasRenderer,f.CanvasRenderer.prototype.render=function(a){f.texturesToUpdate=[],f.texturesToDestroy=[],f.visibleCount++,a.updateTransform(),this.view.style.backgroundColor==a.backgroundColorString||this.transparent||(this.view.style.backgroundColor=a.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(a),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0&&(f.Texture.frameUpdates=[])},f.CanvasRenderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.view.width=a,this.view.height=b},f.CanvasRenderer.prototype.renderDisplayObject=function(a){var b,c=this.context;c.globalCompositeOperation="source-over";var d=a.last._iNext;a=a.first;do if(b=a.worldTransform,a.visible)if(a.renderable){if(a instanceof f.Sprite){var e=a.texture.frame;e&&e.width&&e.height&&(c.globalAlpha=a.worldAlpha,c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),c.drawImage(a.texture.baseTexture.source,e.x,e.y,e.width,e.height,a.anchor.x*-e.width,a.anchor.y*-e.height,e.width,e.height))}else if(a instanceof f.Strip)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderStrip(a);else if(a instanceof f.TilingSprite)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderTilingSprite(a);else if(a instanceof f.CustomRenderable)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),a.renderCanvas(this);else if(a instanceof f.Graphics)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),f.CanvasGraphics.renderGraphics(a,c);else if(a instanceof f.FilterBlock&&a.data instanceof f.Graphics){var g=a.data;if(a.open){c.save();var h=g.alpha,i=g.worldTransform;c.setTransform(i[0],i[3],i[1],i[4],i[2],i[5]),g.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(g,c),c.clip(),g.worldAlpha=h}else c.restore()}a=a._iNext}else a=a._iNext;else a=a.last._iNext;while(a!=d)},f.CanvasRenderer.prototype.renderStripFlat=function(a){var b=this.context,c=a.verticies;a.uvs;var d=c.length/2;this.count++,b.beginPath();for(var e=1;d-2>e;e++){var f=2*e,g=c[f],h=c[f+2],i=c[f+4],j=c[f+1],k=c[f+3],l=c[f+5];b.moveTo(g,j),b.lineTo(h,k),b.lineTo(i,l)}b.fillStyle="#FF0000",b.fill(),b.closePath()},f.CanvasRenderer.prototype.renderTilingSprite=function(a){var b=this.context;b.globalAlpha=a.worldAlpha,a.__tilePattern||(a.__tilePattern=b.createPattern(a.texture.baseTexture.source,"repeat")),b.beginPath();var c=a.tilePosition,d=a.tileScale;b.scale(d.x,d.y),b.translate(c.x,c.y),b.fillStyle=a.__tilePattern,b.fillRect(-c.x,-c.y,a.width/d.x,a.height/d.y),b.scale(1/d.x,1/d.y),b.translate(-c.x,-c.y),b.closePath()},f.CanvasRenderer.prototype.renderStrip=function(a){var b=this.context,c=a.verticies,d=a.uvs,e=c.length/2;this.count++;for(var f=1;e-2>f;f++){var g=2*f,h=c[g],i=c[g+2],j=c[g+4],k=c[g+1],l=c[g+3],m=c[g+5],n=d[g]*a.texture.width,o=d[g+2]*a.texture.width,p=d[g+4]*a.texture.width,q=d[g+1]*a.texture.height,r=d[g+3]*a.texture.height,s=d[g+5]*a.texture.height;b.save(),b.beginPath(),b.moveTo(h,k),b.lineTo(i,l),b.lineTo(j,m),b.closePath(),b.clip();var t=n*r+q*p+o*s-r*p-q*o-n*s,u=h*r+q*j+i*s-r*j-q*i-h*s,v=n*i+h*p+o*j-i*p-h*o-n*j,w=n*r*j+q*i*p+h*o*s-h*r*p-q*o*j-n*i*s,x=k*r+q*m+l*s-r*m-q*l-k*s,y=n*l+k*p+o*m-l*p-k*o-n*m,z=n*r*m+q*l*p+k*o*s-k*r*p-q*o*m-n*l*s;b.transform(u/t,x/t,v/t,y/t,w/t,z/t),b.drawImage(a.texture.baseTexture.source,0,0),b.restore()}},f.CanvasGraphics=function(){},f.CanvasGraphics.renderGraphics=function(a,b){for(var c=a.worldAlpha,d=0;d1&&(c=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var d=0;1>d;d++){var e=a.graphicsData[d],g=e.points;if(e.type==f.Graphics.POLY){b.beginPath(),b.moveTo(g[0],g[1]);for(var h=1;hb?b:d,e=b+m>e?b+m:e,g=g>c?b:g,h=c+n>h?c+n:h}else if(k===f.Graphics.CIRC||k===f.Graphics.ELIP){b=a.x,c=a.y;var o=a.radius+l/2;d=d>b-o?b-o:d,e=b+o>e?b+o:e,g=g>c-o?c-o:g,h=c+o>h?c+o:h}else for(var p=0;pb-l?b-l:d,e=b+l>e?b+l:e,g=g>c-l?c-l:g,h=c+l>h?c+l:h}this.bounds=new f.Rectangle(d,g,e-d,h-g)}},f.Graphics.POLY=0,f.Graphics.RECT=1,f.Graphics.CIRC=2,f.Graphics.ELIP=3,f.Strip=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.blendMode=f.blendModes.NORMAL;try{this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.verticies=new Float32Array([0,0,0,0,0,0,0,0,0]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3])}catch(d){this.uvs=[0,1,1,1,1,0,0,1],this.verticies=[0,0,0,0,0,0,0,0,0],this.colors=[1,1,1,1],this.indices=[0,1,2,3]}this.width=b,this.height=c,a.baseTexture.hasLoaded?(this.width=this.texture.frame.width,this.height=this.texture.frame.height,this.updateFrame=!0):(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Strip.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Strip.prototype.constructor=f.Strip,f.Strip.prototype.setTexture=function(a){this.texture=a,this.width=a.frame.width,this.height=a.frame.height,this.updateFrame=!0},f.Strip.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Rope=function(a,b){f.Strip.call(this,a),this.points=b;try{this.verticies=new Float32Array(4*b.length),this.uvs=new Float32Array(4*b.length),this.colors=new Float32Array(2*b.length),this.indices=new Uint16Array(2*b.length)}catch(c){this.verticies=verticies,this.uvs=uvs,this.colors=colors,this.indices=indices}this.refresh()},f.Rope.prototype=Object.create(f.Strip.prototype),f.Rope.prototype.constructor=f.Rope,f.Rope.prototype.refresh=function(){var a=this.points;if(!(a.length<1)){var b=this.uvs,c=this.indices,d=this.colors,e=a[0],f=a[0];this.count-=.2,b[0]=0,b[1]=1,b[2]=0,b[3]=1,d[0]=1,d[1]=1,c[0]=0,c[1]=1;for(var g=a.length,h=1;g>h;h++){var f=a[h],i=4*h,j=h/(g-1);h%2?(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1):(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1),i=2*h,d[i]=1,d[i+1]=1,i=2*h,c[i]=i,c[i+1]=i+1,e=f}}},f.Rope.prototype.updateTransform=function(){var a=this.points;if(!(a.length<1)){var b,c=this.verticies,d=a[0],e={x:0,y:0},g=a[0];this.count-=.2,c[0]=g.x+e.x,c[1]=g.y+e.y,c[2]=g.x-e.x,c[3]=g.y-e.y;for(var h=a.length,i=1;h>i;i++){var g=a[i],j=4*i;b=i1&&(k=1);var l=Math.sqrt(e.x*e.x+e.y*e.y),m=this.texture.height/2;e.x/=l,e.y/=l,e.x*=m,e.y*=m,c[j]=g.x+e.x,c[j+1]=g.y+e.y,c[j+2]=g.x-e.x,c[j+3]=g.y-e.y,d=g}f.DisplayObjectContainer.prototype.updateTransform.call(this)}},f.Rope.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.width=b,this.height=c,this.tileScale=new f.Point(1,1),this.tilePosition=new f.Point(0,0),this.renderable=!0,this.blendMode=f.blendModes.NORMAL},f.TilingSprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.TilingSprite.prototype.constructor=f.TilingSprite,f.TilingSprite.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Spine=function(a){if(f.DisplayObjectContainer.call(this),this.spineData=f.AnimCache[a],!this.spineData)throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+a);this.skeleton=new n.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new n.AnimationStateData(this.spineData),this.state=new n.AnimationState(this.stateData),this.slotContainers=[];for(var b=0,c=this.skeleton.drawOrder.length;c>b;b++){var d=this.skeleton.drawOrder[b],e=d.attachment,g=new f.DisplayObjectContainer;if(this.slotContainers.push(g),this.addChild(g),e instanceof n.RegionAttachment){var h=e.rendererObject.name,i=this.createSprite(d,e.rendererObject);d.currentSprite=i,d.currentSpriteName=h,g.addChild(i)}}},f.Spine.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Spine.prototype.constructor=f.Spine,f.Spine.prototype.updateTransform=function(){this.lastTime=this.lastTime||Date.now();var a=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.state.update(a),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var b=this.skeleton.drawOrder,c=0,d=b.length;d>c;c++){var e=b[c],g=e.attachment,h=this.slotContainers[c];if(g instanceof n.RegionAttachment){if(g.rendererObject&&(!e.currentSpriteName||e.currentSpriteName!=g.name)){var i=g.rendererObject.name;if(void 0!==e.currentSprite&&(e.currentSprite.visible=!1),e.sprites=e.sprites||{},void 0!==e.sprites[i])e.sprites[i].visible=!0;else{var j=this.createSprite(e,g.rendererObject);h.addChild(j)}e.currentSprite=e.sprites[i],e.currentSpriteName=i}h.visible=!0;var k=e.bone;h.position.x=k.worldX+g.x*k.m00+g.y*k.m01,h.position.y=k.worldY+g.x*k.m10+g.y*k.m11,h.scale.x=k.worldScaleX,h.scale.y=k.worldScaleY,h.rotation=-(e.bone.worldRotation*Math.PI/180)}else h.visible=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.Spine.prototype.createSprite=function(a,b){var c=f.TextureCache[b.name]?b.name:b.name+".png",d=new f.Sprite(f.Texture.fromFrame(c));return d.scale=b.scale,d.rotation=b.rotation,d.anchor.x=d.anchor.y=.5,a.sprites=a.sprites||{},a.sprites[b.name]=d,d};var n={};n.BoneData=function(a,b){this.name=a,this.parent=b},n.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},n.SlotData=function(a,b){this.name=a,this.boneData=b},n.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},n.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},n.Bone.yDown=!1,n.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(a,b){var c=this.parent;null!=c?(this.worldX=this.x*c.m00+this.y*c.m01+c.worldX,this.worldY=this.x*c.m10+this.y*c.m11+c.worldY,this.worldScaleX=c.worldScaleX*this.scaleX,this.worldScaleY=c.worldScaleY*this.scaleY,this.worldRotation=c.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var d=this.worldRotation*Math.PI/180,e=Math.cos(d),f=Math.sin(d);this.m00=e*this.worldScaleX,this.m10=f*this.worldScaleX,this.m01=-f*this.worldScaleY,this.m11=e*this.worldScaleY,a&&(this.m00=-this.m00,this.m01=-this.m01),b&&(this.m10=-this.m10,this.m11=-this.m11),n.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var a=this.data;this.x=a.x,this.y=a.y,this.rotation=a.rotation,this.scaleX=a.scaleX,this.scaleY=a.scaleY}},n.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},n.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(a){this.attachment=a,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(a){this._attachmentTime=this.skeleton.time-a},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var a=this.data;this.r=a.r,this.g=a.g,this.b=a.b,this.a=a.a;for(var b=this.skeleton.data.slots,c=0,d=b.length;d>c;c++)if(b[c]==a){this.setAttachment(a.attachmentName?this.skeleton.getAttachmentBySlotIndex(c,a.attachmentName):null);break}}},n.Skin=function(a){this.name=a,this.attachments={}},n.Skin.prototype={addAttachment:function(a,b,c){this.attachments[a+":"+b]=c},getAttachment:function(a,b){return this.attachments[a+":"+b]},_attachAll:function(a,b){for(var c in b.attachments){var d=c.indexOf(":"),e=parseInt(c.substring(0,d)),f=c.substring(d+1),g=a.slots[e];if(g.attachment&&g.attachment.name==f){var h=this.getAttachment(e,f);h&&g.setAttachment(h)}}}},n.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},n.Animation.prototype={apply:function(a,b,c){c&&0!=this.duration&&(b%=this.duration);for(var d=this.timelines,e=0,f=d.length;f>e;e++)d[e].apply(a,b,1)},mix:function(a,b,c,d){c&&0!=this.duration&&(b%=this.duration);for(var e=this.timelines,f=0,g=e.length;g>f;f++)e[f].apply(a,b,d)}},n.binarySearch=function(a,b,c){var d=0,e=Math.floor(a.length/c)-2;if(0==e)return c;for(var f=e>>>1;;){if(a[(f+1)*c]<=b?d=f+1:e=f,d==e)return(d+1)*c;f=d+e>>>1}},n.linearSearch=function(a,b,c){for(var d=0,e=a.length-c;e>=d;d+=c)if(a[d]>b)return d;return-1},n.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},n.Curves.prototype={setLinear:function(a){this.curves[6*a]=0},setStepped:function(a){this.curves[6*a]=-1},setCurve:function(a,b,c,d,e){var f=.1,g=f*f,h=g*f,i=3*f,j=3*g,k=6*g,l=6*h,m=2*-b+d,n=2*-c+e,o=3*(b-d)+1,p=3*(c-e)+1,q=6*a,r=this.curves;r[q]=b*i+m*j+o*h,r[q+1]=c*i+n*j+p*h,r[q+2]=m*k+o*l,r[q+3]=n*k+p*l,r[q+4]=o*l,r[q+5]=p*l},getCurvePercent:function(a,b){b=0>b?0:b>1?1:b;var c=6*a,d=this.curves,e=d[c];if(!e)return b;if(-1==e)return 0;for(var f=d[c+1],g=d[c+2],h=d[c+3],i=d[c+4],j=d[c+5],k=e,l=f,m=8;;){if(k>=b){var n=k-e,o=l-f;return o+(l-o)*(b-n)/(k-n)}if(0==m)break;m--,e+=g,f+=h,g+=i,h+=j,k+=e,l+=f}return l+(1-l)*(b-k)/(1-k)}},n.RotateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=2*a},n.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(a,b,c){a*=2,this.frames[a]=b,this.frames[a+1]=c},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-2]){for(var f=e.data.rotation+d[d.length-1]-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;return e.rotation+=f*c,void 0}var g=n.binarySearch(d,b,2),h=d[g-1],i=d[g],j=1-(b-i)/(d[g-2]-i);j=this.curves.getCurvePercent(g/2-1,j);for(var f=d[g+1]-h;f>180;)f-=360;for(;-180>f;)f+=360;for(f=e.data.rotation+(h+f*j)-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;e.rotation+=f*c}}},n.TranslateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.x+=(e.data.x+d[d.length-2]-e.x)*c,e.y+=(e.data.y+d[d.length-1]-e.y)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.x+=(e.data.x+g+(d[f+1]-g)*j-e.x)*c,e.y+=(e.data.y+h+(d[f+2]-h)*j-e.y)*c}}},n.ScaleTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.scaleX+=(e.data.scaleX-1+d[d.length-2]-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+d[d.length-1]-e.scaleY)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.scaleX+=(e.data.scaleX-1+g+(d[f+1]-g)*j-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+h+(d[f+2]-h)*j-e.scaleY)*c}}},n.ColorTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=5*a},n.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(c,d){c*=5,this.frames[c]=d,this.frames[c+1]=r,this.frames[c+2]=g,this.frames[c+3]=b,this.frames[c+4]=a},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-5]){var f=d.length-1;return e.r=d[f-3],e.g=d[f-2],e.b=d[f-1],e.a=d[f],void 0}var g=n.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],l=d[g],m=1-(b-l)/(d[g-5]-l);m=this.curves.getCurvePercent(g/5-1,m);var o=h+(d[g+1]-h)*m,p=i+(d[g+2]-i)*m,q=j+(d[g+3]-j)*m,r=k+(d[g+4]-k)*m;1>c?(e.r+=(o-e.r)*c,e.g+=(p-e.g)*c,e.b+=(q-e.b)*c,e.a+=(r-e.a)*c):(e.r=o,e.g=p,e.b=q,e.a=r)}}},n.AttachmentTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},n.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(a,b,c){this.frames[a]=b,this.attachmentNames[a]=c},apply:function(a,b){var c=this.frames;if(!(b=c[c.length-1]?c.length-1:n.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},n.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},n.SkeletonData.prototype={defaultSkin:null,findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return slot[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSkin:function(a){for(var b=this.skins,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findAnimation:function(a){for(var b=this.animations,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null}},n.Skeleton=function(a){this.data=a,this.bones=[];for(var b=0,c=a.bones.length;c>b;b++){var d=a.bones[b],e=d.parent?this.bones[a.bones.indexOf(d.parent)]:null;this.bones.push(new n.Bone(d,e))}this.slots=[],this.drawOrder=[];for(var b=0,c=a.slots.length;c>b;b++){var f=a.slots[b],g=this.bones[a.bones.indexOf(f.boneData)],h=new n.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},n.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var a=this.flipX,b=this.flipY,c=this.bones,d=0,e=c.length;e>d;d++)c[d].updateWorldTransform(a,b)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var a=this.bones,b=0,c=a.length;c>b;b++)a[b].setToSetupPose()},setSlotsToSetupPose:function(){for(var a=this.slots,b=0,c=a.length;c>b;b++)a[b].setToSetupPose(b)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},setSkinByName:function(a){var b=this.data.findSkin(a);if(!b)throw"Skin not found: "+a;this.setSkin(b)},setSkin:function(a){this.skin&&a&&a._attachAll(this,this.skin),this.skin=a},getAttachmentBySlotName:function(a,b){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(a),b)},getAttachmentBySlotIndex:function(a,b){if(this.skin){var c=this.skin.getAttachment(a,b);if(c)return c}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(a,b):null},setAttachment:function(a,b){for(var c=this.slots,d=0,e=c.size;e>d;d++){var f=c[d];if(f.data.name==a){var g=null;if(b&&(g=this.getAttachment(d,b),null==g))throw"Attachment not found: "+b+", for slot: "+a;return f.setAttachment(g),void 0}}throw"Slot not found: "+a},update:function(a){time+=a}},n.AttachmentType={region:0},n.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},n.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(a,b,c,d,e){var f=this.uvs;e?(f[2]=a,f[3]=d,f[4]=a,f[5]=b,f[6]=c,f[7]=b,f[0]=c,f[1]=d):(f[0]=a,f[1]=d,f[2]=a,f[3]=b,f[4]=c,f[5]=b,f[6]=c,f[7]=d)},updateOffset:function(){var a=this.width/this.regionOriginalWidth*this.scaleX,b=this.height/this.regionOriginalHeight*this.scaleY,c=-this.width/2*this.scaleX+this.regionOffsetX*a,d=-this.height/2*this.scaleY+this.regionOffsetY*b,e=c+this.regionWidth*a,f=d+this.regionHeight*b,g=this.rotation*Math.PI/180,h=Math.cos(g),i=Math.sin(g),j=c*h+this.x,k=c*i,l=d*h+this.y,m=d*i,n=e*h+this.x,o=e*i,p=f*h+this.y,q=f*i,r=this.offset;r[0]=j-m,r[1]=l+k,r[2]=j-q,r[3]=p+k,r[4]=n-q,r[5]=p+o,r[6]=n-m,r[7]=l+o},computeVertices:function(a,b,c,d){a+=c.worldX,b+=c.worldY;var e=c.m00,f=c.m01,g=c.m10,h=c.m11,i=this.offset;d[0]=i[0]*e+i[1]*f+a,d[1]=i[0]*g+i[1]*h+b,d[2]=i[2]*e+i[3]*f+a,d[3]=i[2]*g+i[3]*h+b,d[4]=i[4]*e+i[5]*f+a,d[5]=i[4]*g+i[5]*h+b,d[6]=i[6]*e+i[7]*f+a,d[7]=i[6]*g+i[7]*h+b}},n.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},n.AnimationStateData.prototype={defaultMix:0,setMixByName:function(a,b,c){var d=this.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;var e=this.skeletonData.findAnimation(b);if(!e)throw"Animation not found: "+b;this.setMix(d,e,c)},setMix:function(a,b,c){this.animationToMixTime[a.name+":"+b.name]=c},getMix:function(a,b){var c=this.animationToMixTime[a.name+":"+b.name];return c?c:this.defaultMix}},n.AnimationState=function(a){this.data=a,this.queue=[]},n.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(a){if(this.currentTime+=a,this.previousTime+=a,this.mixTime+=a,this.queue.length>0){var b=this.queue[0];this.currentTime>=b.delay&&(this._setAnimation(b.animation,b.loop),this.queue.shift())}},apply:function(a){if(this.current)if(this.previous){this.previous.apply(a,this.previousTime,this.previousLoop);var b=this.mixTime/this.mixDuration;b>=1&&(b=1,this.previous=null),this.current.mix(a,this.currentTime,this.currentLoop,b)}else this.current.apply(a,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(a,b){this.previous=null,a&&this.current&&(this.mixDuration=this.data.getMix(this.current,a),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=a,this.currentLoop=b,this.currentTime=0},setAnimationByName:function(a,b){var c=this.data.skeletonData.findAnimation(a);if(!c)throw"Animation not found: "+a;this.setAnimation(c,b)},setAnimation:function(a,b){this.queue.length=0,this._setAnimation(a,b)},addAnimationByName:function(a,b,c){var d=this.data.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;this.addAnimation(d,b,c)},addAnimation:function(a,b,c){var d={};if(d.animation=a,d.loop=b,!c||0>=c){var e=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;c=null!=e?e.duration-this.data.getMix(e,a)+(c||0):0}d.delay=c,this.queue.push(d)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},n.SkeletonJson=function(a){this.attachmentLoader=a},n.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new n.SkeletonData,c=a.bones,d=0,e=c.length;e>d;d++){var f=c[d],g=null;if(f.parent&&(g=b.findBone(f.parent),!g))throw"Parent bone not found: "+f.parent;var h=new n.BoneData(f.name,g);h.length=(f.length||0)*this.scale,h.x=(f.x||0)*this.scale,h.y=(f.y||0)*this.scale,h.rotation=f.rotation||0,h.scaleX=f.scaleX||1,h.scaleY=f.scaleY||1,b.bones.push(h)}for(var i=a.slots,d=0,e=i.length;e>d;d++){var j=i[d],h=b.findBone(j.bone); -if(!h)throw"Slot bone not found: "+j.bone;var k=new n.SlotData(j.name,h),l=j.color;l&&(k.r=n.SkeletonJson.toColor(l,0),k.g=n.SkeletonJson.toColor(l,1),k.b=n.SkeletonJson.toColor(l,2),k.a=n.SkeletonJson.toColor(l,3)),k.attachmentName=j.attachment,b.slots.push(k)}var m=a.skins;for(var o in m)if(m.hasOwnProperty(o)){var p=m[o],q=new n.Skin(o);for(var r in p)if(p.hasOwnProperty(r)){var s=b.findSlotIndex(r),t=p[r];for(var u in t)if(t.hasOwnProperty(u)){var v=this.readAttachment(q,u,t[u]);null!=v&&q.addAttachment(s,u,v)}}b.skins.push(q),"default"==q.name&&(b.defaultSkin=q)}var w=a.animations;for(var x in w)w.hasOwnProperty(x)&&this.readAnimation(x,w[x],b);return b},readAttachment:function(a,b,c){b=c.name||b;var d=n.AttachmentType[c.type||"region"];if(d==n.AttachmentType.region){var e=new n.RegionAttachment;return e.x=(c.x||0)*this.scale,e.y=(c.y||0)*this.scale,e.scaleX=c.scaleX||1,e.scaleY=c.scaleY||1,e.rotation=c.rotation||0,e.width=(c.width||32)*this.scale,e.height=(c.height||32)*this.scale,e.updateOffset(),e.rendererObject={},e.rendererObject.name=b,e.rendererObject.scale={},e.rendererObject.scale.x=e.scaleX,e.rendererObject.scale.y=e.scaleY,e.rendererObject.rotation=-e.rotation*Math.PI/180,e}throw"Unknown attachment type: "+d},readAnimation:function(a,b,c){var d=[],e=0,f=b.bones;for(var g in f)if(f.hasOwnProperty(g)){var h=c.findBoneIndex(g);if(-1==h)throw"Bone not found: "+g;var i=f[g];for(var j in i)if(i.hasOwnProperty(j)){var k=i[j];if("rotate"==j){var l=new n.RotateTimeline(k.length);l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m,q.time,q.angle),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[2*l.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var l,r=1;"scale"==j?l=new n.ScaleTimeline(k.length):(l=new n.TranslateTimeline(k.length),r=this.scale),l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;l.setFrame(m,q.time,s,t),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[3*l.getFrameCount()-3])}}}var u=b.slots;for(var v in u)if(u.hasOwnProperty(v)){var w=u[v],x=c.findSlotIndex(v);for(var j in w)if(w.hasOwnProperty(j)){var k=w[j];if("color"==j){var l=new n.ColorTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=n.SkeletonJson.toColor(y,0),A=n.SkeletonJson.toColor(y,1),B=n.SkeletonJson.toColor(y,2),C=n.SkeletonJson.toColor(y,3);l.setFrame(m,q.time,z,A,B,C),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[5*l.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var l=new n.AttachmentTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m++,q.time,q.name)}d.push(l),e=Math.max(e,l.frames[l.getFrameCount()-1])}}}c.animations.push(new n.Animation(a,d,e))}},n.SkeletonJson.readCurve=function(a,b,c){var d=c.curve;d&&("stepped"==d?a.curves.setStepped(b):d instanceof Array&&a.curves.setCurve(b,d[0],d[1],d[2],d[3]))},n.SkeletonJson.toColor=function(a,b){if(8!=a.length)throw"Color hexidecimal length must be 8, recieved: "+a;return parseInt(a.substring(2*b,2),16)/255},n.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new n.AtlasReader(a),d=[];d.length=4;for(var e=null;;){var f=c.readLine();if(null==f)break;if(f=c.trim(f),0==f.length)e=null;else if(e){var g=new n.AtlasRegion;g.name=f,g.page=e,g.rotate="true"==c.readValue(),c.readTuple(d);var h=parseInt(d[0]),i=parseInt(d[1]);c.readTuple(d);var j=parseInt(d[0]),k=parseInt(d[1]);g.u=h/e.width,g.v=i/e.height,g.rotate?(g.u2=(h+k)/e.width,g.v2=(i+j)/e.height):(g.u2=(h+j)/e.width,g.v2=(i+k)/e.height),g.x=h,g.y=i,g.width=Math.abs(j),g.height=Math.abs(k),4==c.readTuple(d)&&(g.splits=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],4==c.readTuple(d)&&(g.pads=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],c.readTuple(d))),g.originalWidth=parseInt(d[0]),g.originalHeight=parseInt(d[1]),c.readTuple(d),g.offsetX=parseInt(d[0]),g.offsetY=parseInt(d[1]),g.index=parseInt(c.readValue()),this.regions.push(g)}else{e=new n.AtlasPage,e.name=f,e.format=n.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=n.Atlas.TextureFilter[d[0]],e.magFilter=n.Atlas.TextureFilter[d[1]];var l=c.readValue();e.uWrap=n.Atlas.TextureWrap.clampToEdge,e.vWrap=n.Atlas.TextureWrap.clampToEdge,"x"==l?e.uWrap=n.Atlas.TextureWrap.repeat:"y"==l?e.vWrap=n.Atlas.TextureWrap.repeat:"xy"==l&&(e.uWrap=e.vWrap=n.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},n.Atlas.prototype={findRegion:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},dispose:function(){for(var a=this.pages,b=0,c=a.length;c>b;b++)this.textureLoader.unload(a[b].rendererObject)},updateUVs:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++){var e=b[c];e.page==a&&(e.u=e.x/a.width,e.v=e.y/a.height,e.rotate?(e.u2=(e.x+e.height)/a.width,e.v2=(e.y+e.width)/a.height):(e.u2=(e.x+e.width)/a.width,e.v2=(e.y+e.height)/a.height))}}},n.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},n.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},n.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},n.AtlasPage=function(){},n.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},n.AtlasRegion=function(){},n.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},n.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},n.AtlasReader.prototype={index:0,trim:function(a){return a.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var a=this.readLine(),b=a.indexOf(":");if(-1==b)throw"Invalid line: "+a;return this.trim(a.substring(b+1))},readTuple:function(a){var b=this.readLine(),c=b.indexOf(":");if(-1==c)throw"Invalid line: "+b;for(var d=0,e=c+1;3>d;d++){var f=b.indexOf(",",e);if(-1==f){if(0==d)throw"Invalid line: "+b;break}a[d]=this.trim(b.substr(e,f-e)),e=f+1}return a[d]=this.trim(b.substring(e)),d+1}},n.AtlasAttachmentLoader=function(a){this.atlas=a},n.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case n.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new n.RegionAttachment(c);return e.rendererObject=d,e.setUVs(d.u,d.v,d.u2,d.v2,d.rotate),e.regionOffsetX=d.offsetX,e.regionOffsetY=d.offsetY,e.regionWidth=d.width,e.regionHeight=d.height,e.regionOriginalWidth=d.originalWidth,e.regionOriginalHeight=d.originalHeight,e}throw"Unknown attachment type: "+b}},f.AnimCache={},n.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this),this.renderable=!0},f.CustomRenderable.prototype=Object.create(f.DisplayObject.prototype),f.CustomRenderable.prototype.constructor=f.CustomRenderable,f.CustomRenderable.prototype.renderCanvas=function(){},f.CustomRenderable.prototype.initWebGL=function(){},f.CustomRenderable.prototype.renderWebGL=function(){},f.BaseTextureCache={},f.texturesToUpdate=[],f.texturesToDestroy=[],f.BaseTexture=function(a){if(f.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=a,a){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);else{var b=this;this.source.onload=function(){b.hasLoaded=!0,b.width=b.source.width,b.height=b.source.height,f.texturesToUpdate.push(b),b.dispatchEvent({type:"loaded",content:b})}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);this._powerOf2=!1}},f.BaseTexture.prototype.constructor=f.BaseTexture,f.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,f.texturesToDestroy.push(this)},f.BaseTexture.fromImage=function(a,b){var c=f.BaseTextureCache[a];if(!c){var d=new Image;b&&(d.crossOrigin=""),d.src=a,c=new f.BaseTexture(d),f.BaseTextureCache[a]=c}return c},f.TextureCache={},f.FrameCache={},f.Texture=function(a,b){if(f.EventTarget.call(this),b||(this.noFrame=!0,b=new f.Rectangle(0,0,1,1)),a instanceof f.Texture&&(a=a.baseTexture),this.baseTexture=a,this.frame=b,this.trim=new f.Point,this.scope=this,a.hasLoaded)this.noFrame&&(b=new f.Rectangle(0,0,a.width,a.height)),this.setFrame(b);else{var c=this;a.addEventListener("loaded",function(){c.onBaseTextureLoaded()})}},f.Texture.prototype.constructor=f.Texture,f.Texture.prototype.onBaseTextureLoaded=function(){var a=this.baseTexture;a.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new f.Rectangle(0,0,a.width,a.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},f.Texture.prototype.destroy=function(a){a&&this.baseTexture.destroy()},f.Texture.prototype.setFrame=function(a){if(this.frame=a,this.width=a.width,this.height=a.height,a.x+a.width>this.baseTexture.width||a.y+a.height>this.baseTexture.height)throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,f.Texture.frameUpdates.push(this)},f.Texture.fromImage=function(a,b){var c=f.TextureCache[a];return c||(c=new f.Texture(f.BaseTexture.fromImage(a,b)),f.TextureCache[a]=c),c},f.Texture.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache "+this);return b},f.Texture.fromCanvas=function(a){var b=new f.BaseTexture(a);return new f.Texture(b)},f.Texture.addTextureToCache=function(a,b){f.TextureCache[b]=a},f.Texture.removeTextureFromCache=function(a){var b=f.TextureCache[a];return f.TextureCache[a]=null,b},f.Texture.frameUpdates=[],f.RenderTexture=function(a,b){f.EventTarget.call(this),this.width=a||100,this.height=b||100,this.indetityMatrix=f.mat3.create(),this.frame=new f.Rectangle(0,0,this.width,this.height),f.gl?this.initWebGL():this.initCanvas()},f.RenderTexture.prototype=Object.create(f.Texture.prototype),f.RenderTexture.prototype.constructor=f.RenderTexture,f.RenderTexture.prototype.initWebGL=function(){var a=f.gl;this.glFramebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new f.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.baseTexture._glTexture),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,this.width,this.height,0,a.RGBA,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new f.Point(this.width/2,-this.height/2),this.render=this.renderWebGL},f.RenderTexture.prototype.resize=function(a,b){if(this.width=a,this.height=b,f.gl){this.projection.x=this.width/2,this.projection.y=-this.height/2;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.baseTexture._glTexture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,this.width,this.height,0,c.RGBA,c.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height)},f.RenderTexture.prototype.initCanvas=function(){this.renderer=new f.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new f.BaseTexture(this.renderer.view),this.frame=new f.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},f.RenderTexture.prototype.renderWebGL=function(a,b,c){var d=f.gl;d.colorMask(!0,!0,!0,!0),d.viewport(0,0,this.width,this.height),d.bindFramebuffer(d.FRAMEBUFFER,this.glFramebuffer),c&&(d.clearColor(0,0,0,0),d.clear(d.COLOR_BUFFER_BIT));var e=a.children,g=a.worldTransform;a.worldTransform=f.mat3.create(),a.worldTransform[4]=-1,a.worldTransform[5]=-2*this.projection.y,b&&(a.worldTransform[2]=b.x,a.worldTransform[5]-=b.y),f.visibleCount++,a.vcount=f.visibleCount;for(var h=0,i=e.length;i>h;h++)e[h].updateTransform();var j=a.__renderGroup;j?a==j.root?j.render(this.projection,this.glFramebuffer):j.renderSpecific(a,this.projection,this.glFramebuffer):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection,this.glFramebuffer)),a.worldTransform=g},f.RenderTexture.prototype.renderCanvas=function(a,b,c){var d=a.children;a.worldTransform=f.mat3.create(),b&&(a.worldTransform[2]=b.x,a.worldTransform[5]=b.y);for(var e=0,g=d.length;g>e;e++)d[e].updateTransform();c&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(a),this.renderer.context.setTransform(1,0,0,1,0,0)},f.AssetLoader=function(a,b){f.EventTarget.call(this),this.assetURLs=a,this.crossorigin=b,this.loadersByType={jpg:f.ImageLoader,jpeg:f.ImageLoader,png:f.ImageLoader,gif:f.ImageLoader,json:f.JsonLoader,anim:f.SpineLoader,xml:f.BitmapFontLoader,fnt:f.BitmapFontLoader}},f.AssetLoader.prototype.constructor=f.AssetLoader,f.AssetLoader.prototype.load=function(){var a=this;this.loadCount=this.assetURLs.length;for(var b=0;bh;h++)for(var i=0;d>i;i++,g++){var j=new f.Texture(this.texture,{x:i*a,y:h*b,width:a,height:b});this.frames.push(j),c&&(f.TextureCache[c+"-"+g]=j)}if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var k=this;this.texture.baseTexture.addEventListener("loaded",function(){k.onLoaded()})}},f.BitmapFontLoader=function(a,b){f.EventTarget.call(this),this.url=a,this.crossorigin=b,this.baseUrl=a.replace(/[^\/]*$/,""),this.texture=null},f.BitmapFontLoader.prototype.constructor=f.BitmapFontLoader,f.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var a=this;this.ajaxRequest.onreadystatechange=function(){a.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},f.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var a=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,b=new f.ImageLoader(a,this.crossorigin);this.texture=b.texture.baseTexture;var c={},d=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],e=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];c.font=d.attributes.getNamedItem("face").nodeValue,c.size=parseInt(d.attributes.getNamedItem("size").nodeValue,10),c.lineHeight=parseInt(e.attributes.getNamedItem("lineHeight").nodeValue,10),c.chars={};for(var g=this.ajaxRequest.responseXML.getElementsByTagName("char"),h=0;h>16&255)/255,(a>>8&255)/255,(255&a)/255]}function d(a){return[(a>>16&255)/255,(a>>8&255)/255,(255&a)/255]}var e=this,f=f||{};f.Point=function(a,b){this.x=a||0,this.y=b||0},f.Point.prototype.clone=function(){return new f.Point(this.x,this.y)},f.Point.prototype.constructor=f.Point,f.Rectangle=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Rectangle.prototype.clone=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Rectangle.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=this.x;if(a>=c&&a<=c+this.width){var d=this.y;if(b>=d&&b<=d+this.height)return!0}return!1},f.Rectangle.prototype.constructor=f.Rectangle,f.Polygon=function(a){if(a instanceof Array||(a=Array.prototype.slice.call(arguments)),"number"==typeof a[0]){for(var b=[],c=0,d=a.length;d>c;c+=2)b.push(new f.Point(a[c],a[c+1]));a=b}this.points=a},f.Polygon.prototype.clone=function(){for(var a=[],b=0;bb!=i>b&&(h-f)*(b-g)/(i-g)+f>a;j&&(c=!c)}return c},f.Polygon.prototype.constructor=f.Polygon,f.Circle=function(a,b,c){this.x=a||0,this.y=b||0,this.radius=c||0},f.Circle.prototype.clone=function(){return new f.Circle(this.x,this.y,this.radius)},f.Circle.prototype.contains=function(a,b){if(this.radius<=0)return!1;var c=this.x-a,d=this.y-b,e=this.radius*this.radius;return c*=c,d*=d,e>=c+d},f.Circle.prototype.constructor=f.Circle,f.Ellipse=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Ellipse.prototype.clone=function(){return new f.Ellipse(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=(a-this.x)/this.width-.5,d=(b-this.y)/this.height-.5;return c*=c,d*=d,.25>c+d},f.Ellipse.getBounds=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.constructor=f.Ellipse,c(),f.mat3={},f.mat3.create=function(){var a=new f.Matrix(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat3.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat4={},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat3.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=m*d+n*g+o*j,c[1]=m*e+n*h+o*k,c[2]=m*f+n*i+o*l,c[3]=p*d+q*g+r*j,c[4]=p*e+q*h+r*k,c[5]=p*f+q*i+r*l,c[6]=s*d+t*g+u*j,c[7]=s*e+t*h+u*k,c[8]=s*f+t*i+u*l,c},f.mat3.clone=function(a){var b=new f.Matrix(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.mat3.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.mat3.toMat4=function(a,b){return b||(b=f.mat4.create()),b[15]=1,b[14]=0,b[13]=0,b[12]=0,b[11]=0,b[10]=a[8],b[9]=a[7],b[8]=a[6],b[7]=0,b[6]=a[5],b[5]=a[4],b[4]=a[3],b[3]=0,b[2]=a[2],b[1]=a[1],b[0]=a[0],b},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat4.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},f.mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,t=b[4],u=b[5],v=b[6],w=b[7],c[4]=t*d+u*h+v*l+w*p,c[5]=t*e+u*i+v*m+w*q,c[6]=t*f+u*j+v*n+w*r,c[7]=t*g+u*k+v*o+w*s,t=b[8],u=b[9],v=b[10],w=b[11],c[8]=t*d+u*h+v*l+w*p,c[9]=t*e+u*i+v*m+w*q,c[10]=t*f+u*j+v*n+w*r,c[11]=t*g+u*k+v*o+w*s,t=b[12],u=b[13],v=b[14],w=b[15],c[12]=t*d+u*h+v*l+w*p,c[13]=t*e+u*i+v*m+w*q,c[14]=t*f+u*j+v*n+w*r,c[15]=t*g+u*k+v*o+w*s,c},f.DisplayObject=function(){this.last=this,this.first=this,this.position=new f.Point,this.scale=new f.Point(1,1),this.pivot=new f.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.parent=null,this.stage=null,this.worldAlpha=1,this._interactive=!1,this.worldTransform=f.mat3.create(),this.localTransform=f.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1,this.filterArea=new f.Rectangle(0,0,1,1)},f.DisplayObject.prototype.constructor=f.DisplayObject,f.DisplayObject.prototype.setInteractive=function(a){this.interactive=a},Object.defineProperty(f.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(a){this._interactive=a,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(f.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(a){a?this._mask?(a.start=this._mask.start,a.end=this._mask.end):(this.addFilter(a),a.renderable=!1):(this.removeFilter(this._mask),this._mask.renderable=!0),this._mask=a}}),Object.defineProperty(f.DisplayObject.prototype,"filters",{get:function(){return this._filters},set:function(a){if(a){this._filters&&this.removeFilter(this._filters),this.addFilter(a);for(var b=[],c=0;c=0&&b<=this.children.length))throw new Error(a+" The index "+b+" supplied is out of bounds "+this.children.length);if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.stage){var c=a;do c.interactive&&(this.stage.dirty=!0),c.stage=this.stage,c=c._iNext;while(c)}var d,e,f=a.first,g=a.last;if(b==this.children.length){e=this.last;for(var h=this,i=this.last;h;)h.last==i&&(h.last=a.last),h=h.parent}else e=0==b?this:this.children[b-1].last;d=e._iNext,d&&(d._iPrev=g,g._iNext=d),f._iPrev=e,e._iNext=f,this.children.splice(b,0,a),this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.swapChildren=function(){},f.DisplayObjectContainer.prototype.getChildAt=function(a){if(a>=0&&aa;a++)this.children[a].updateTransform()}},f.blendModes={},f.blendModes.NORMAL=0,f.blendModes.SCREEN=1,f.Sprite=function(a){f.DisplayObjectContainer.call(this),this.anchor=new f.Point,this.texture=a,this.blendMode=f.blendModes.NORMAL,this._width=0,this._height=0,a.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Sprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Sprite.prototype.constructor=f.Sprite,Object.defineProperty(f.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(a){this.scale.x=a/this.texture.frame.width,this._width=a}}),Object.defineProperty(f.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(a){this.scale.y=a/this.texture.frame.height,this._height=a}}),f.Sprite.prototype.setTexture=function(a){this.texture.baseTexture!=a.baseTexture?(this.textureChange=!0,this.texture=a,this.__renderGroup&&this.__renderGroup.updateTexture(this)):this.texture=a,this.updateFrame=!0},f.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},f.Sprite.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache"+this);return new f.Sprite(b)},f.Sprite.fromImage=function(a){var b=f.Texture.fromImage(a);return new f.Sprite(b)},f.MovieClip=function(a){f.Sprite.call(this,a[0]),this.textures=a,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},f.MovieClip.prototype=Object.create(f.Sprite.prototype),f.MovieClip.prototype.constructor=f.MovieClip,Object.defineProperty(f.MovieClip.prototype,"totalFrames",{get:function(){return this.textures.length}}),f.MovieClip.prototype.stop=function(){this.playing=!1},f.MovieClip.prototype.play=function(){this.playing=!0},f.MovieClip.prototype.gotoAndStop=function(a){this.playing=!1,this.currentFrame=a;var b=this.currentFrame+.5|0;this.setTexture(this.textures[b%this.textures.length])},f.MovieClip.prototype.gotoAndPlay=function(a){this.currentFrame=a,this.playing=!0},f.MovieClip.prototype.updateTransform=function(){if(f.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var a=this.currentFrame+.5|0;this.loop||a=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},f.FilterBlock=function(){this.visible=!0,this.renderable=!0},f.Text=function(a,b){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),f.Sprite.call(this,f.Texture.fromCanvas(this.canvas)),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.Text.prototype=Object.create(f.Sprite.prototype),f.Text.prototype.constructor=f.Text,f.Text.prototype.setStyle=function(a){a=a||{},a.font=a.font||"bold 20pt Arial",a.fill=a.fill||"black",a.align=a.align||"left",a.stroke=a.stroke||"black",a.strokeThickness=a.strokeThickness||0,a.wordWrap=a.wordWrap||!1,a.wordWrapWidth=a.wordWrapWidth||100,this.style=a,this.dirty=!0},f.Text.prototype.setText=function(a){this.text=a.toString()||" ",this.dirty=!0},f.Text.prototype.updateText=function(){this.context.font=this.style.font;var a=this.text;this.style.wordWrap&&(a=this.wordWrap(this.text));for(var b=a.split(/(?:\r\n|\r|\n)/),c=[],d=0,e=0;ee?(g>0&&(b+="\n"),b+=f[g]+" ",e=this.style.wordWrapWidth-h):(e-=i,b+=f[g]+" ")}b+="\n"}return b},f.Text.prototype.destroy=function(a){a&&this.texture.destroy()},f.Text.heightCache={},f.BitmapText=function(a,b){f.DisplayObjectContainer.call(this),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.BitmapText.prototype=Object.create(f.DisplayObjectContainer.prototype),f.BitmapText.prototype.constructor=f.BitmapText,f.BitmapText.prototype.setText=function(a){this.text=a||" ",this.dirty=!0},f.BitmapText.prototype.setStyle=function(a){a=a||{},a.align=a.align||"left",this.style=a;var b=a.font.split(" ");this.fontName=b[b.length-1],this.fontSize=b.length>=2?parseInt(b[b.length-2],10):f.BitmapText.fonts[this.fontName].size,this.dirty=!0},f.BitmapText.prototype.updateText=function(){for(var a=f.BitmapText.fonts[this.fontName],b=new f.Point,c=null,d=[],e=0,g=[],h=0,i=this.fontSize/a.size,j=0;j=j;j++){var n=0;"right"==this.style.align?n=e-g[j]:"center"==this.style.align&&(n=(e-g[j])/2),m.push(n)}for(j=0;j0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.BitmapText.fonts={},f.InteractionManager=function(a){this.stage=a,this.mouse=new f.InteractionData,this.touchs={},this.tempPoint=new f.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0},f.InteractionManager.prototype.constructor=f.InteractionManager,f.InteractionManager.prototype.collectInteractiveSprite=function(a,b){for(var c=a.children,d=c.length,e=d-1;e>=0;e--){var f=c[e];f.interactive?(b.interactiveChildren=!0,this.interactiveItems.push(f),f.children.length>0&&this.collectInteractiveSprite(f,f)):(f.__iParent=null,f.children.length>0&&this.collectInteractiveSprite(f,b))}},f.InteractionManager.prototype.setTarget=function(a){this.target=a,null===this.interactionDOMElement&&this.setTargetDomElement(a.view),document.body.addEventListener("mouseup",this.onMouseUp,!0)},f.InteractionManager.prototype.setTargetDomElement=function(a){null!==this.interactionDOMElement&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]="",this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0)),window.navigator.msPointerEnabled&&(a.style["-ms-content-zooming"]="none",a.style["-ms-touch-action"]="none"),this.interactionDOMElement=a,a.addEventListener("mousemove",this.onMouseMove,!0),a.addEventListener("mousedown",this.onMouseDown,!0),a.addEventListener("mouseout",this.onMouseOut,!0),a.addEventListener("touchstart",this.onTouchStart,!0),a.addEventListener("touchend",this.onTouchEnd,!0),a.addEventListener("touchmove",this.onTouchMove,!0)},f.InteractionManager.prototype.update=function(){if(this.target){var a=Date.now(),b=a-this.last;if(b=30*b/1e3,!(1>b)){if(this.last=a,this.dirty){this.dirty=!1;for(var c=this.interactiveItems.length,d=0;c>d;d++)this.interactiveItems[d].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var e=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var d=0;e>d;d++){var f=this.interactiveItems[d];(f.mouseover||f.mouseout||f.buttonMode)&&(f.__hit=this.hitTest(f,this.mouse),this.mouse.target=f,f.__hit?(f.buttonMode&&(this.interactionDOMElement.style.cursor="pointer"),f.__isOver||(f.mouseover&&f.mouseover(this.mouse),f.__isOver=!0)):f.__isOver&&(f.mouseout&&f.mouseout(this.mouse),f.__isOver=!1))}}}},f.InteractionManager.prototype.onMouseMove=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(a.clientX-b.left)*(this.target.width/b.width),this.mouse.global.y=(a.clientY-b.top)*(this.target.height/b.height);for(var c=this.interactiveItems.length,d=(this.mouse.global,0);c>d;d++){var e=this.interactiveItems[d];e.mousemove&&e.mousemove(this.mouse)}},f.InteractionManager.prototype.onMouseDown=function(a){this.mouse.originalEvent=a||window.event;for(var b=this.interactiveItems.length,c=(this.mouse.global,this.stage,0);b>c;c++){var d=this.interactiveItems[c];if((d.mousedown||d.click)&&(d.__mouseIsDown=!0,d.__hit=this.hitTest(d,this.mouse),d.__hit&&(d.mousedown&&d.mousedown(this.mouse),d.__isDown=!0,!d.interactiveChildren)))break}},f.InteractionManager.prototype.onMouseOut=function(){var a=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var b=0;a>b;b++){var c=this.interactiveItems[b];c.__isOver&&(this.mouse.target=c,c.mouseout&&c.mouseout(this.mouse),c.__isOver=!1)}},f.InteractionManager.prototype.onMouseUp=function(a){this.mouse.originalEvent=a||window.event;for(var b=(this.mouse.global,this.interactiveItems.length),c=!1,d=0;b>d;d++){var e=this.interactiveItems[d];(e.mouseup||e.mouseupoutside||e.click)&&(e.__hit=this.hitTest(e,this.mouse),e.__hit&&!c?(e.mouseup&&e.mouseup(this.mouse),e.__isDown&&e.click&&e.click(this.mouse),e.interactiveChildren||(c=!0)):e.__isDown&&e.mouseupoutside&&e.mouseupoutside(this.mouse),e.__isDown=!1)}},f.InteractionManager.prototype.hitTest=function(a,b){var c=b.global;if(a.vcount!==f.visibleCount)return!1;var d=a instanceof f.Sprite,e=a.worldTransform,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=1/(g*k+h*-j),n=k*m*c.x+-h*m*c.y+(l*h-i*k)*m,o=g*m*c.y+-j*m*c.x+(-l*g+i*j)*m;if(b.target=a,a.hitArea&&a.hitArea.contains)return a.hitArea.contains(n,o)?(b.target=a,!0):!1;if(d){var p,q=a.texture.frame.width,r=a.texture.frame.height,s=-q*a.anchor.x;if(n>s&&s+q>n&&(p=-r*a.anchor.y,o>p&&p+r>o))return b.target=a,!0}for(var t=a.children.length,u=0;t>u;u++){var v=a.children[u],w=this.hitTest(v,b);if(w)return b.target=a,!0}return!1},f.InteractionManager.prototype.onTouchMove=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;dd;d++){var h=this.interactiveItems[d];h.touchmove&&h.touchmove(f)}},f.InteractionManager.prototype.onTouchStart=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i];if((j.touchstart||j.tap)&&(j.__hit=this.hitTest(j,g),j.__hit&&(j.touchstart&&j.touchstart(g),j.__isDown=!0,j.__touchData=g,!j.interactiveChildren)))break}}},f.InteractionManager.prototype.onTouchEnd=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i],k=j.__touchData;j.__hit=this.hitTest(j,f),k==f&&(f.originalEvent=a||window.event,(j.touchend||j.tap)&&(j.__hit&&!g?(j.touchend&&j.touchend(f),j.__isDown&&j.tap&&j.tap(f),j.interactiveChildren||(g=!0)):j.__isDown&&j.touchendoutside&&j.touchendoutside(f),j.__isDown=!1),j.__touchData=null)}this.pool.push(f),this.touchs[e.identifier]=null}},f.InteractionData=function(){this.global=new f.Point,this.local=new f.Point,this.target,this.originalEvent},f.InteractionData.prototype.getLocalPosition=function(a){var b=a.worldTransform,c=this.global,d=b[0],e=b[1],g=b[2],h=b[3],i=b[4],j=b[5],k=1/(d*i+e*-h);return new f.Point(i*k*c.x+-e*k*c.y+(j*e-g*i)*k,d*k*c.y+-h*k*c.x+(-j*d+g*h)*k)},f.InteractionData.prototype.constructor=f.InteractionData,f.Stage=function(a){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=!0,this.interactionManager=new f.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new f.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(a),this.worldVisible=!0},f.Stage.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Stage.prototype.constructor=f.Stage,f.Stage.prototype.setInteractionDelegate=function(a){this.interactionManager.setTargetDomElement(a)},f.Stage.prototype.updateTransform=function(){this.worldAlpha=1,this.vcount=f.visibleCount;for(var a=0,b=this.children.length;b>a;a++)this.children[a].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},f.Stage.prototype.setBackgroundColor=function(a){this.backgroundColor=a||0,this.backgroundColorSplit=d(this.backgroundColor);var b=this.backgroundColor.toString(16);b="000000".substr(0,6-b.length)+b,this.backgroundColorString="#"+b},f.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var h=0,i=["ms","moz","webkit","o"],j=0;j>>>>>>>>"),console.log("_");var b=0,c=a.first;for(console.log(c);c._iNext;)if(b++,c=c._iNext,console.log(c),b>100){console.log("BREAK");break}},f.EventTarget=function(){var a={};this.addEventListener=this.on=function(b,c){void 0===a[b]&&(a[b]=[]),-1===a[b].indexOf(c)&&a[b].push(c)},this.dispatchEvent=this.emit=function(b){if(a[b.type]&&a[b.type].length)for(var c=0,d=a[b.type].length;d>c;c++)a[b.type][c](b)},this.removeEventListener=this.off=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}},f.autoDetectRenderer=function(a,b,c,d,e){a||(a=800),b||(b=600);var g=function(){try{var a=document.createElement("canvas");return!!window.WebGLRenderingContext&&(a.getContext("webgl")||a.getContext("experimental-webgl"))}catch(b){return!1}}();if(g){var h=-1!=navigator.userAgent.toLowerCase().indexOf("msie");g=!h}return g?new f.WebGLRenderer(a,b,c,d,e):new f.CanvasRenderer(a,b,c,d)},f.PolyK={},f.PolyK.Triangulate=function(a){var b=!0,c=a.length>>1;if(3>c)return[];for(var d=[],e=[],g=0;c>g;g++)e.push(g);for(var g=0,h=c;h>3;){var i=e[(g+0)%h],j=e[(g+1)%h],k=e[(g+2)%h],l=a[2*i],m=a[2*i+1],n=a[2*j],o=a[2*j+1],p=a[2*k],q=a[2*k+1],r=!1;if(f.PolyK._convex(l,m,n,o,p,q,b)){r=!0;for(var s=0;h>s;s++){var t=e[s];if(t!=i&&t!=j&&t!=k&&f.PolyK._PointInTriangle(a[2*t],a[2*t+1],l,m,n,o,p,q)){r=!1;break}}}if(r)d.push(i,j,k),e.splice((g+1)%h,1),h--,g=0;else if(g++>3*h){if(!b)return console.log("PIXI Warning: shape too complex to fill"),[];var d=[];e=[];for(var g=0;c>g;g++)e.push(g);g=0,h=c,b=!1}}return d.push(e[0],e[1],e[2]),d},f.PolyK._PointInTriangle=function(a,b,c,d,e,f,g,h){var i=g-c,j=h-d,k=e-c,l=f-d,m=a-c,n=b-d,o=i*i+j*j,p=i*k+j*l,q=i*m+j*n,r=k*k+l*l,s=k*m+l*n,t=1/(o*r-p*p),u=(r*q-p*s)*t,v=(o*s-p*q)*t;return u>=0&&v>=0&&1>u+v},f.PolyK._convex=function(a,b,c,d,e,f,g){return(b-d)*(e-c)+(c-a)*(f-d)>=0==g},f.initDefaultShaders=function(){f.primitiveShader=new f.PrimitiveShader,f.primitiveShader.init(),f.stripShader=new f.StripShader,f.stripShader.init(),f.defaultShader=new f.PixiShader,f.defaultShader.init();var a=f.gl,b=f.defaultShader.program;a.useProgram(b),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.primitiveShader.program),a.disableVertexAttribArray(f.defaultShader.aVertexPosition),a.disableVertexAttribArray(f.defaultShader.colorAttribute),a.disableVertexAttribArray(f.defaultShader.aTextureCoord),a.enableVertexAttribArray(f.primitiveShader.aVertexPosition),a.enableVertexAttribArray(f.primitiveShader.colorAttribute)},f.deactivatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program),a.disableVertexAttribArray(f.primitiveShader.aVertexPosition),a.disableVertexAttribArray(f.primitiveShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activateStripShader=function(){var a=f.gl;a.useProgram(f.stripShader.program)},f.deactivateStripShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program)},f.CompileVertexShader=function(a,b){return f._CompileShader(a,b,a.VERTEX_SHADER)},f.CompileFragmentShader=function(a,b){return f._CompileShader(a,b,a.FRAGMENT_SHADER)},f._CompileShader=function(a,b,c){var d=b.join("\n"),e=a.createShader(c);return a.shaderSource(e,d),a.compileShader(e),a.getShaderParameter(e,a.COMPILE_STATUS)?e:(console.log(a.getShaderInfoLog(e)),null)},f.compileProgram=function(a,b){var c=f.gl,d=f.CompileFragmentShader(c,b),e=f.CompileVertexShader(c,a),g=c.createProgram();return c.attachShader(g,e),c.attachShader(g,d),c.linkProgram(g),c.getProgramParameter(g,c.LINK_STATUS)||console.log("Could not initialise shaders"),g},f.PixiShader=function(){this.program,this.fragmentSrc=["precision lowp float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;","}"],this.textureCount=0},f.PixiShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc||f.PixiShader.defaultVertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"); +for(var c in this.uniforms)this.uniforms[c].uniformLocation=b.getUniformLocation(a,c);this.program=a},f.PixiShader.prototype.syncUniforms=function(){this.textureCount=1;var a=f.gl;for(var b in this.uniforms){var c=this.uniforms[b].type,d=!1;if(this.uniforms[b].transpose&&(d=this.uniforms[b].transpose),"1f"==c)a.uniform1f(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1fv"==c)a.uniform1fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1i"==c)a.uniform1i(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1iv"==c)a.uniform1i(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("2f"==c)a.uniform2f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("2fv"==c)a.uniform2fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("2i"==c)a.uniform2i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("2iv"==c)a.uniform2iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("3f"==c)a.uniform3f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z);else if("3fv"==c)a.uniform3fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("3i"==c)a.uniform3i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z);else if("3iv"==c)a.uniform3iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("4f"==c)a.uniform4f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z,this.uniforms[b].value.w);else if("4fv"==c)a.uniform4fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("4i"==c)a.uniform4i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z,this.uniforms[b].value.w);else if("4iv"==c)a.uniform4iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("mat2"==c)a.uniformMatrix2fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("mat3"==c)a.uniformMatrix3fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("mat4"==c)a.uniformMatrix4fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("sampler2D"==c&&this.uniforms[b].value.baseTexture.hasLoaded){var e=this.uniforms[b].value.baseTexture._glTexture,g=this.uniforms[b].value.baseTexture.source,h=a.RGBA;this.uniforms[b].format&&"luminance"==this.uniforms[b].format&&(h=a.LUMINANCE),a.activeTexture(a["TEXTURE"+this.textureCount]),this.uniforms[b].wrap?"no-repeat"==this.uniforms[b].wrap||this.uniforms[b].wrap===!1?this.createGLTextureLinear(a,g,e):"repeat"==this.uniforms[b].wrap||this.uniforms[b].wrap===!0?this.createGLTexture(a,g,h,e):"nearest-repeat"==this.uniforms[b].wrap?this.createGLTextureNearestRepeat(a,g,e):"nearest"==this.uniforms[b].wrap?this.createGLTextureNearest(a,g,e):"audio"==this.uniforms[b].wrap?this.createAudioTexture(a,e):"keyboard"==this.uniforms[b].wrap&&this.createKeyboardTexture(a,e):this.createGLTextureLinear(a,g,e),a.uniform1i(this.uniforms[b].uniformLocation,this.textureCount),this.textureCount++}}},f.PixiShader.prototype.createGLTexture=function(a,b,c,d){a.bindTexture(a.TEXTURE_2D,d),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,c,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR_MIPMAP_LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.REPEAT),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.REPEAT),a.generateMipmap(a.TEXTURE_2D)},f.PixiShader.prototype.createGLTextureLinear=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)},f.PixiShader.prototype.createGLTextureNearestRepeat=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.REPEAT),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.REPEAT)},f.PixiShader.prototype.createGLTextureNearest=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)},f.PixiShader.prototype.createAudioTexture=function(a,b){a.bindTexture(a.TEXTURE_2D,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),a.texImage2D(a.TEXTURE_2D,0,a.LUMINANCE,512,2,0,a.LUMINANCE,a.UNSIGNED_BYTE,null)},f.PixiShader.prototype.createKeyboardTexture=function(a,b){a.bindTexture(a.TEXTURE_2D,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),a.texImage2D(a.TEXTURE_2D,0,a.LUMINANCE,256,2,0,a.LUMINANCE,a.UNSIGNED_BYTE,null)},f.PixiShader.defaultVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","varying vec2 vTextureCoord;","varying float vColor;","const vec2 center = vec2(-1.0, 1.0);","void main(void) {","gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.StripShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying vec2 offsetVector;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"]},f.StripShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.PrimitiveShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"]},f.PrimitiveShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.WebGLGraphics=function(){},f.WebGLGraphics.renderGraphics=function(a,b){var c=f.gl;a._webGL||(a._webGL={points:[],indices:[],lastIndex:0,buffer:c.createBuffer(),indexBuffer:c.createBuffer()}),a.dirty&&(a.dirty=!1,a.clearDirty&&(a.clearDirty=!1,a._webGL.lastIndex=0,a._webGL.points=[],a._webGL.indices=[]),f.WebGLGraphics.updateGraphics(a)),f.activatePrimitiveShader();var d=f.mat3.clone(a.worldTransform);f.mat3.transpose(d),c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA),c.uniformMatrix3fv(f.primitiveShader.translationMatrix,!1,d),c.uniform2f(f.primitiveShader.projectionVector,b.x,-b.y),c.uniform2f(f.primitiveShader.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(f.primitiveShader.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.primitiveShader.aVertexPosition,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveShader.colorAttribute,4,c.FLOAT,!1,24,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),c.drawElements(c.TRIANGLE_STRIP,a._webGL.indices.length,c.UNSIGNED_SHORT,0),f.deactivatePrimitiveShader()},f.WebGLGraphics.updateGraphics=function(a){for(var b=a._webGL.lastIndex;b3&&f.WebGLGraphics.buildPoly(c,a._webGL),c.lineWidth>0&&f.WebGLGraphics.buildLine(c,a._webGL)):c.type==f.Graphics.RECT?f.WebGLGraphics.buildRectangle(c,a._webGL):(c.type==f.Graphics.CIRC||c.type==f.Graphics.ELIP)&&f.WebGLGraphics.buildCircle(c,a._webGL)}a._webGL.lastIndex=a.graphicsData.length;var d=f.gl;a._webGL.glPoints=new Float32Array(a._webGL.points),d.bindBuffer(d.ARRAY_BUFFER,a._webGL.buffer),d.bufferData(d.ARRAY_BUFFER,a._webGL.glPoints,d.STATIC_DRAW),a._webGL.glIndicies=new Uint16Array(a._webGL.indices),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),d.bufferData(d.ELEMENT_ARRAY_BUFFER,a._webGL.glIndicies,d.STATIC_DRAW)},f.WebGLGraphics.buildRectangle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3];if(a.fill){var j=d(a.fillColor),k=a.fillAlpha,l=j[0]*k,m=j[1]*k,n=j[2]*k,o=b.points,p=b.indices,q=o.length/6;o.push(e,g),o.push(l,m,n,k),o.push(e+h,g),o.push(l,m,n,k),o.push(e,g+i),o.push(l,m,n,k),o.push(e+h,g+i),o.push(l,m,n,k),p.push(q,q,q+1,q+2,q+3,q+3)}a.lineWidth&&(a.points=[e,g,e+h,g,e+h,g+i,e,g+i,e,g],f.WebGLGraphics.buildLine(a,b))},f.WebGLGraphics.buildCircle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3],j=40,k=2*Math.PI/j;if(a.fill){var l=d(a.fillColor),m=a.fillAlpha,n=l[0]*m,o=l[1]*m,p=l[2]*m,q=b.points,r=b.indices,s=q.length/6;r.push(s);for(var t=0;j+1>t;t++)q.push(e,g,n,o,p,m),q.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i,n,o,p,m),r.push(s++,s++);r.push(s-1)}if(a.lineWidth){a.points=[];for(var t=0;j+1>t;t++)a.points.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i);f.WebGLGraphics.buildLine(a,b)}},f.WebGLGraphics.buildLine=function(a,b){var c=a.points;if(0!=c.length){if(a.lineWidth%2)for(var e=0;ee;e++)k=c[2*(e-1)],l=c[2*(e-1)+1],m=c[2*e],n=c[2*e+1],o=c[2*(e+1)],p=c[2*(e+1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,s=-(n-p),t=m-o,E=Math.sqrt(s*s+t*t),s/=E,t/=E,s*=K,t*=K,w=-r+l-(-r+n),x=-q+m-(-q+k),y=(-q+k)*(-r+n)-(-q+m)*(-r+l),z=-t+p-(-t+n),A=-s+m-(-s+o),B=(-s+o)*(-t+n)-(-s+m)*(-t+p),C=w*A-z*x,Math.abs(C)<.1?(C+=10.1,F.push(m-q,n-r,N,O,P,M),F.push(m+q,n+r,N,O,P,M)):(px=(x*B-A*y)/C,py=(z*y-w*B)/C,D=(px-m)*(px-m)+(py-n)+(py-n),D>19600?(u=q-s,v=r-t,E=Math.sqrt(u*u+v*v),u/=E,v/=E,u*=K,v*=K,F.push(m-u,n-v),F.push(N,O,P,M),F.push(m+u,n+v),F.push(N,O,P,M),F.push(m-u,n-v),F.push(N,O,P,M),I++):(F.push(px,py),F.push(N,O,P,M),F.push(m-(px-m),n-(py-n)),F.push(N,O,P,M)));k=c[2*(H-2)],l=c[2*(H-2)+1],m=c[2*(H-1)],n=c[2*(H-1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,F.push(m-q,n-r),F.push(N,O,P,M),F.push(m+q,n+r),F.push(N,O,P,M),G.push(J);for(var e=0;I>e;e++)G.push(J++);G.push(J-1)}},f.WebGLGraphics.buildPoly=function(a,b){var c=a.points;if(!(c.length<6)){for(var e=b.points,g=b.indices,h=c.length/2,i=d(a.fillColor),j=a.fillAlpha,k=i[0]*j,l=i[1]*j,m=i[2]*j,n=f.PolyK.Triangulate(c),o=e.length/6,p=0;pp;p++)e.push(c[2*p],c[2*p+1],k,l,m,j)}},f._defaultFrame=new f.Rectangle(0,0,1,1),f.gl,f.WebGLRenderer=function(a,b,c,d,e){this.transparent=!!d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var g=this;this.view.addEventListener("webglcontextlost",function(a){g.handleContextLost(a)},!1),this.view.addEventListener("webglcontextrestored",function(a){g.handleContextRestored(a)},!1),this.batchs=[];var h={alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0};try{f.gl=this.gl=this.view.getContext("experimental-webgl",h)}catch(i){try{f.gl=this.gl=this.view.getContext("webgl",h)}catch(i){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}}f.initDefaultShaders();var j=this.gl;j.useProgram(f.defaultShader.program),f.WebGLRenderer.gl=j,this.batch=new f.WebGLBatch(j),j.disable(j.DEPTH_TEST),j.disable(j.CULL_FACE),j.enable(j.BLEND),j.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),f.offset=new f.Point(0,0),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new f.WebGLRenderGroup(this.gl,this.transparent)},f.WebGLRenderer.prototype.constructor=f.WebGLRenderer,f.WebGLRenderer.getBatch=function(){return 0==f._batchs.length?new f.WebGLBatch(f.WebGLRenderer.gl):f._batchs.pop()},f.WebGLRenderer.returnBatch=function(a){a.clean(),f._batchs.push(a)},f.WebGLRenderer.prototype.render=function(a){if(!this.contextLost){this.__stage!==a&&(this.__stage=a,this.stageRenderGroup.setRenderable(a)),f.WebGLRenderer.updateTextures(),f.visibleCount++,a.updateTransform();var b=this.gl;if(b.colorMask(!0,!0,!0,this.transparent),b.viewport(0,0,this.width,this.height),b.bindFramebuffer(b.FRAMEBUFFER,null),b.clearColor(a.backgroundColorSplit[0],a.backgroundColorSplit[1],a.backgroundColorSplit[2],!this.transparent),b.clear(b.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=a.backgroundColorSplit,f.projection.x=this.width/2,f.projection.y=-this.height/2,this.stageRenderGroup.render(f.projection),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0){for(var c=0;cc;c++){var d=6*c,e=4*c;this.indices[d+0]=e+0,this.indices[d+1]=e+1,this.indices[d+2]=e+2,this.indices[d+3]=e+0,this.indices[d+4]=e+2,this.indices[d+5]=e+3}a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,this.indices,a.STATIC_DRAW)},f.WebGLBatch.prototype.refresh=function(){this.gl;this.dynamicSizen;n++)renderable=this.batchs[n],renderable instanceof f.WebGLBatch?this.batchs[n].render():this.renderSpecial(renderable,b);endBatch instanceof f.WebGLBatch?endBatch.render(0,h+1):this.renderSpecial(endBatch,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){var c=a.vcount===f.visibleCount;a instanceof f.TilingSprite?c&&this.renderTilingSprite(a,b):a instanceof f.Strip?c&&this.renderStrip(a,b):a instanceof f.CustomRenderable?c&&a.renderWebGL(this,b):a instanceof f.Graphics?c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b):a instanceof f.FilterBlock&&this.handleFilterBlock(a,b)},flip=!1;var l=[],m=0;f.WebGLRenderGroup.prototype.handleFilterBlock=function(a,b){var c=f.gl;if(a.open)a.data instanceof Array?this.filterManager.pushFilter(a):(m++,l.push(a),c.enable(c.STENCIL_TEST),c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.INCR),f.WebGLGraphics.renderGraphics(a.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP));else if(a.data instanceof Array)this.filterManager.popFilter();else{var d=l.pop(a);d&&(c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.DECR),f.WebGLGraphics.renderGraphics(d.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP)),c.disable(c.STENCIL_TEST)}},f.WebGLRenderGroup.prototype.updateTexture=function(a){this.removeObject(a);for(var b=a.first;b!=this.root&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););this.insertObject(a,b,c)},f.WebGLRenderGroup.prototype.addFilterBlocks=function(a,b){a.__renderGroup=this,b.__renderGroup=this;for(var c=a;c!=this.root.first&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root.first&&(d=d._iPrev,!d.renderable||!d.__renderGroup););this.insertAfter(b,d)},f.WebGLRenderGroup.prototype.removeFilterBlocks=function(a,b){this.removeObject(a),this.removeObject(b)},f.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(a){a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a);for(var b=a.first;b!=this.root.first&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););var d=a.first,e=a.last._iNext;do d.__renderGroup=this,d.renderable&&(this.insertObject(d,b,c),b=d),d=d._iNext;while(d!=e)},f.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(a){if(a.__renderGroup==this){{a.last}do a.__renderGroup=null,a.renderable&&this.removeObject(a),a=a._iNext;while(a)}},f.WebGLRenderGroup.prototype.insertObject=function(a,b,c){var d=b,e=c;if(a instanceof f.Sprite){var g,h;if(d instanceof f.Sprite){if(g=d.batch,g&&g.texture==a.texture.baseTexture&&g.blendMode==a.blendMode)return g.insertAfter(a,d),void 0}else g=d;if(e)if(e instanceof f.Sprite){if(h=e.batch){if(h.texture==a.texture.baseTexture&&h.blendMode==a.blendMode)return h.insertBefore(a,e),void 0;if(h==g){var i=g.split(e),j=f.WebGLRenderer.getBatch(),k=this.batchs.indexOf(g);return j.init(a),this.batchs.splice(k+1,0,j,i),void 0}}}else h=e;var j=f.WebGLRenderer.getBatch();if(j.init(a),g){var k=this.batchs.indexOf(g);this.batchs.splice(k+1,0,j)}else this.batchs.push(j)}else a instanceof f.TilingSprite?this.initTilingSprite(a):a instanceof f.Strip&&this.initStrip(a),this.insertAfter(a,d)},f.WebGLRenderGroup.prototype.insertAfter=function(a,b){if(b instanceof f.Sprite){var c=b.batch;if(c)if(c.tail==b){var d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a)}else{var e=c.split(b.__next),d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a,e)}else this.batchs.push(a)}else{var d=this.batchs.indexOf(b);this.batchs.splice(d+1,0,a)}},f.WebGLRenderGroup.prototype.removeObject=function(a){var b;if(a instanceof f.Sprite){var c=a.batch;if(!c)return;c.remove(a),0==c.size&&(b=c)}else b=a;if(b){var d=this.batchs.indexOf(b);if(-1==d)return;if(0==d||d==this.batchs.length-1)return this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),void 0;if(this.batchs[d-1]instanceof f.WebGLBatch&&this.batchs[d+1]instanceof f.WebGLBatch&&this.batchs[d-1].texture==this.batchs[d+1].texture&&this.batchs[d-1].blendMode==this.batchs[d+1].blendMode)return this.batchs[d-1].merge(this.batchs[d+1]),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),f.WebGLRenderer.returnBatch(this.batchs[d+1]),this.batchs.splice(d,2),void 0;this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b)}},f.WebGLRenderGroup.prototype.initTilingSprite=function(a){var b=this.gl;a.verticies=new Float32Array([0,0,a.width,0,a.width,a.height,0,a.height]),a.uvs=new Float32Array([0,0,1,0,1,1,0,1]),a.colors=new Float32Array([1,1,1,1]),a.indices=new Uint16Array([0,1,3,2]),a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW),a.texture.baseTexture._glTexture?(b.bindTexture(b.TEXTURE_2D,a.texture.baseTexture._glTexture),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.REPEAT),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.REPEAT),a.texture.baseTexture._powerOf2=!0):a.texture.baseTexture._powerOf2=!0},f.WebGLRenderGroup.prototype.renderStrip=function(a,b){var c=this.gl;f.activateStripShader();var d=f.stripShader,e=(d.program,f.mat3.clone(a.worldTransform));f.mat3.transpose(e),c.uniformMatrix3fv(d.translationMatrix,!1,e),c.uniform2f(d.projectionVector,b.x,b.y),c.uniform2f(d.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(d.alpha,a.worldAlpha),a.dirty?(a.dirty=!1,c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferData(c.ARRAY_BUFFER,a.verticies,c.STATIC_DRAW),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferData(c.ARRAY_BUFFER,a.uvs,c.STATIC_DRAW),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.bufferData(c.ARRAY_BUFFER,a.colors,c.STATIC_DRAW),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,a.indices,c.STATIC_DRAW)):(c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.verticies),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer)),c.drawElements(c.TRIANGLE_STRIP,a.indices.length,c.UNSIGNED_SHORT,0),f.deactivateStripShader() +},f.WebGLRenderGroup.prototype.renderTilingSprite=function(a,b){var c=this.gl,d=(f.shaderProgram,a.tilePosition),e=a.tileScale,g=d.x/a.texture.baseTexture.width,h=d.y/a.texture.baseTexture.height,i=a.width/a.texture.baseTexture.width/e.x,j=a.height/a.texture.baseTexture.height/e.y;a.uvs[0]=0-g,a.uvs[1]=0-h,a.uvs[2]=1*i-g,a.uvs[3]=0-h,a.uvs[4]=1*i-g,a.uvs[5]=1*j-h,a.uvs[6]=0-g,a.uvs[7]=1*j-h,c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.uvs),this.renderStrip(a,b)},f.WebGLRenderGroup.prototype.initStrip=function(a){{var b=this.gl;this.shaderProgram}a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW)},f.WebGLFilterManager=function(a){this.transparent=a,this.filterStack=[],this.texturePool=[],this.offsetX=0,this.offsetY=0,this.initShaderBuffers()},f.WebGLFilterManager.prototype.begin=function(a,b){this.width=2*a.x,this.height=2*-a.y,this.buffer=b},f.WebGLFilterManager.prototype.pushFilter=function(a){var b=f.gl;this.filterStack.push(a);var c=a.filterPasses[0];this.offsetX+=a.target.filterArea.x,this.offsetY+=a.target.filterArea.y;var d=this.texturePool.pop();d||(d=new f.FilterTexture(this.width,this.height)),b.bindTexture(b.TEXTURE_2D,d.texture),this.getBounds(a.target);var e=a.target.filterArea,g=c.padding;e.x-=g,e.y-=g,e.width+=2*g,e.height+=2*g,e.x<0&&(e.x=0),e.width>this.width&&(e.width=this.width),e.y<0&&(e.y=0),e.height>this.height&&(e.height=this.height),b.bindFramebuffer(b.FRAMEBUFFER,d.frameBuffer),b.viewport(0,0,e.width,e.height),f.projection.x=e.width/2,f.projection.y=-e.height/2,f.offset.x=-e.x,f.offset.y=-e.y,b.uniform2f(f.defaultShader.projectionVector,e.width/2,-e.height/2),b.uniform2f(f.defaultShader.offsetVector,-e.x,-e.y),b.colorMask(!0,!0,!0,!0),b.clearColor(0,0,0,0),b.clear(b.COLOR_BUFFER_BIT),a._glFilterTexture=d},f.WebGLFilterManager.prototype.popFilter=function(){var a=f.gl,b=this.filterStack.pop(),c=b.target.filterArea,d=b._glFilterTexture;if(b.filterPasses.length>1){a.viewport(0,0,c.width,c.height),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer),this.vertexArray[0]=0,this.vertexArray[1]=c.height,this.vertexArray[2]=c.width,this.vertexArray[3]=c.height,this.vertexArray[4]=0,this.vertexArray[5]=0,this.vertexArray[6]=c.width,this.vertexArray[7]=0,a.bufferSubData(a.ARRAY_BUFFER,0,this.vertexArray),a.bindBuffer(a.ARRAY_BUFFER,this.uvBuffer),this.uvArray[2]=c.width/this.width,this.uvArray[5]=c.height/this.height,this.uvArray[6]=c.width/this.width,this.uvArray[7]=c.height/this.height,a.bufferSubData(a.ARRAY_BUFFER,0,this.uvArray);var e=d,g=this.texturePool.pop();g||(g=new f.FilterTexture(this.width,this.height)),a.bindFramebuffer(a.FRAMEBUFFER,g.frameBuffer),a.clear(a.COLOR_BUFFER_BIT),a.disable(a.BLEND);for(var h=0;hs?s:E,E=E>t?t:E,E=E>u?u:E,E=E>v?v:E,F=F>w?w:F,F=F>x?x:F,F=F>y?y:F,F=F>z?z:F,C=s>C?s:C,C=t>C?t:C,C=u>C?u:C,C=v>C?v:C,D=w>D?w:D,D=x>D?x:D,D=y>D?y:D,D=z>D?z:D),l=!1,A=A._iNext}while(A!=B);a.filterArea.x=E,a.filterArea.y=F,a.filterArea.width=C-E,a.filterArea.height=D-F},f.FilterTexture=function(a,b){var c=f.gl;this.frameBuffer=c.createFramebuffer(),this.texture=c.createTexture(),c.bindTexture(c.TEXTURE_2D,this.texture),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.bindFramebuffer(c.FRAMEBUFFER,this.framebuffer),c.bindFramebuffer(c.FRAMEBUFFER,this.frameBuffer),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,this.texture,0),this.resize(a,b)},f.FilterTexture.prototype.resize=function(a,b){this.width=a,this.height=b;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.texture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,a,b,0,c.RGBA,c.UNSIGNED_BYTE,null)},f.CanvasRenderer=function(a,b,c,d){this.transparent=d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},f.CanvasRenderer.prototype.constructor=f.CanvasRenderer,f.CanvasRenderer.prototype.render=function(a){f.texturesToUpdate=[],f.texturesToDestroy=[],f.visibleCount++,a.updateTransform(),this.view.style.backgroundColor==a.backgroundColorString||this.transparent||(this.view.style.backgroundColor=a.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(a),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0&&(f.Texture.frameUpdates=[])},f.CanvasRenderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.view.width=a,this.view.height=b},f.CanvasRenderer.prototype.renderDisplayObject=function(a){var b,c=this.context;c.globalCompositeOperation="source-over";var d=a.last._iNext;a=a.first;do if(b=a.worldTransform,a.visible)if(a.renderable){if(a instanceof f.Sprite){var e=a.texture.frame;e&&e.width&&e.height&&(c.globalAlpha=a.worldAlpha,c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),c.drawImage(a.texture.baseTexture.source,e.x,e.y,e.width,e.height,a.anchor.x*-e.width,a.anchor.y*-e.height,e.width,e.height))}else if(a instanceof f.Strip)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderStrip(a);else if(a instanceof f.TilingSprite)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderTilingSprite(a);else if(a instanceof f.CustomRenderable)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),a.renderCanvas(this);else if(a instanceof f.Graphics)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),f.CanvasGraphics.renderGraphics(a,c);else if(a instanceof f.FilterBlock&&a.data instanceof f.Graphics){var g=a.data;if(a.open){c.save();var h=g.alpha,i=g.worldTransform;c.setTransform(i[0],i[3],i[1],i[4],i[2],i[5]),g.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(g,c),c.clip(),g.worldAlpha=h}else c.restore()}a=a._iNext}else a=a._iNext;else a=a.last._iNext;while(a!=d)},f.CanvasRenderer.prototype.renderStripFlat=function(a){var b=this.context,c=a.verticies,d=(a.uvs,c.length/2);this.count++,b.beginPath();for(var e=1;d-2>e;e++){var f=2*e,g=c[f],h=c[f+2],i=c[f+4],j=c[f+1],k=c[f+3],l=c[f+5];b.moveTo(g,j),b.lineTo(h,k),b.lineTo(i,l)}b.fillStyle="#FF0000",b.fill(),b.closePath()},f.CanvasRenderer.prototype.renderTilingSprite=function(a){var b=this.context;b.globalAlpha=a.worldAlpha,a.__tilePattern||(a.__tilePattern=b.createPattern(a.texture.baseTexture.source,"repeat")),b.beginPath();var c=a.tilePosition,d=a.tileScale;b.scale(d.x,d.y),b.translate(c.x,c.y),b.fillStyle=a.__tilePattern,b.fillRect(-c.x,-c.y,a.width/d.x,a.height/d.y),b.scale(1/d.x,1/d.y),b.translate(-c.x,-c.y),b.closePath()},f.CanvasRenderer.prototype.renderStrip=function(a){var b=this.context,c=a.verticies,d=a.uvs,e=c.length/2;this.count++;for(var f=1;e-2>f;f++){var g=2*f,h=c[g],i=c[g+2],j=c[g+4],k=c[g+1],l=c[g+3],m=c[g+5],n=d[g]*a.texture.width,o=d[g+2]*a.texture.width,p=d[g+4]*a.texture.width,q=d[g+1]*a.texture.height,r=d[g+3]*a.texture.height,s=d[g+5]*a.texture.height;b.save(),b.beginPath(),b.moveTo(h,k),b.lineTo(i,l),b.lineTo(j,m),b.closePath(),b.clip();var t=n*r+q*p+o*s-r*p-q*o-n*s,u=h*r+q*j+i*s-r*j-q*i-h*s,v=n*i+h*p+o*j-i*p-h*o-n*j,w=n*r*j+q*i*p+h*o*s-h*r*p-q*o*j-n*i*s,x=k*r+q*m+l*s-r*m-q*l-k*s,y=n*l+k*p+o*m-l*p-k*o-n*m,z=n*r*m+q*l*p+k*o*s-k*r*p-q*o*m-n*l*s;b.transform(u/t,x/t,v/t,y/t,w/t,z/t),b.drawImage(a.texture.baseTexture.source,0,0),b.restore()}},f.CanvasGraphics=function(){},f.CanvasGraphics.renderGraphics=function(a,b){for(var c=a.worldAlpha,d=0;d1&&(c=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var d=0;1>d;d++){var e=a.graphicsData[d],g=e.points;if(e.type==f.Graphics.POLY){b.beginPath(),b.moveTo(g[0],g[1]);for(var h=1;hb?b:d,e=b+m>e?b+m:e,g=g>c?b:g,h=c+n>h?c+n:h}else if(k===f.Graphics.CIRC||k===f.Graphics.ELIP){b=a.x,c=a.y;var o=a.radius+l/2;d=d>b-o?b-o:d,e=b+o>e?b+o:e,g=g>c-o?c-o:g,h=c+o>h?c+o:h}else for(var p=0;pb-l?b-l:d,e=b+l>e?b+l:e,g=g>c-l?c-l:g,h=c+l>h?c+l:h}this.bounds=new f.Rectangle(d,g,e-d,h-g)}},f.Graphics.POLY=0,f.Graphics.RECT=1,f.Graphics.CIRC=2,f.Graphics.ELIP=3,f.Strip=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.blendMode=f.blendModes.NORMAL;try{this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.verticies=new Float32Array([0,0,0,0,0,0,0,0,0]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3])}catch(d){this.uvs=[0,1,1,1,1,0,0,1],this.verticies=[0,0,0,0,0,0,0,0,0],this.colors=[1,1,1,1],this.indices=[0,1,2,3]}this.width=b,this.height=c,a.baseTexture.hasLoaded?(this.width=this.texture.frame.width,this.height=this.texture.frame.height,this.updateFrame=!0):(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Strip.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Strip.prototype.constructor=f.Strip,f.Strip.prototype.setTexture=function(a){this.texture=a,this.width=a.frame.width,this.height=a.frame.height,this.updateFrame=!0},f.Strip.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Rope=function(a,b){f.Strip.call(this,a),this.points=b;try{this.verticies=new Float32Array(4*b.length),this.uvs=new Float32Array(4*b.length),this.colors=new Float32Array(2*b.length),this.indices=new Uint16Array(2*b.length)}catch(c){this.verticies=verticies,this.uvs=uvs,this.colors=colors,this.indices=indices}this.refresh()},f.Rope.prototype=Object.create(f.Strip.prototype),f.Rope.prototype.constructor=f.Rope,f.Rope.prototype.refresh=function(){var a=this.points;if(!(a.length<1)){var b=this.uvs,c=this.indices,d=this.colors,e=a[0],f=a[0];this.count-=.2,b[0]=0,b[1]=1,b[2]=0,b[3]=1,d[0]=1,d[1]=1,c[0]=0,c[1]=1;for(var g=a.length,h=1;g>h;h++){var f=a[h],i=4*h,j=h/(g-1);h%2?(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1):(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1),i=2*h,d[i]=1,d[i+1]=1,i=2*h,c[i]=i,c[i+1]=i+1,e=f}}},f.Rope.prototype.updateTransform=function(){var a=this.points;if(!(a.length<1)){var b,c=this.verticies,d=a[0],e={x:0,y:0},g=a[0];this.count-=.2,c[0]=g.x+e.x,c[1]=g.y+e.y,c[2]=g.x-e.x,c[3]=g.y-e.y;for(var h=a.length,i=1;h>i;i++){var g=a[i],j=4*i;b=i1&&(k=1);var l=Math.sqrt(e.x*e.x+e.y*e.y),m=this.texture.height/2;e.x/=l,e.y/=l,e.x*=m,e.y*=m,c[j]=g.x+e.x,c[j+1]=g.y+e.y,c[j+2]=g.x-e.x,c[j+3]=g.y-e.y,d=g}f.DisplayObjectContainer.prototype.updateTransform.call(this)}},f.Rope.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.width=b,this.height=c,this.tileScale=new f.Point(1,1),this.tilePosition=new f.Point(0,0),this.renderable=!0,this.blendMode=f.blendModes.NORMAL},f.TilingSprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.TilingSprite.prototype.constructor=f.TilingSprite,f.TilingSprite.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Spine=function(a){if(f.DisplayObjectContainer.call(this),this.spineData=f.AnimCache[a],!this.spineData)throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+a);this.skeleton=new n.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new n.AnimationStateData(this.spineData),this.state=new n.AnimationState(this.stateData),this.slotContainers=[];for(var b=0,c=this.skeleton.drawOrder.length;c>b;b++){var d=this.skeleton.drawOrder[b],e=d.attachment,g=new f.DisplayObjectContainer;if(this.slotContainers.push(g),this.addChild(g),e instanceof n.RegionAttachment){var h=e.rendererObject.name,i=this.createSprite(d,e.rendererObject);d.currentSprite=i,d.currentSpriteName=h,g.addChild(i)}}},f.Spine.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Spine.prototype.constructor=f.Spine,f.Spine.prototype.updateTransform=function(){this.lastTime=this.lastTime||Date.now();var a=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.state.update(a),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var b=this.skeleton.drawOrder,c=0,d=b.length;d>c;c++){var e=b[c],g=e.attachment,h=this.slotContainers[c];if(g instanceof n.RegionAttachment){if(g.rendererObject&&(!e.currentSpriteName||e.currentSpriteName!=g.name)){var i=g.rendererObject.name;if(void 0!==e.currentSprite&&(e.currentSprite.visible=!1),e.sprites=e.sprites||{},void 0!==e.sprites[i])e.sprites[i].visible=!0;else{var j=this.createSprite(e,g.rendererObject);h.addChild(j)}e.currentSprite=e.sprites[i],e.currentSpriteName=i}h.visible=!0;var k=e.bone;h.position.x=k.worldX+g.x*k.m00+g.y*k.m01,h.position.y=k.worldY+g.x*k.m10+g.y*k.m11,h.scale.x=k.worldScaleX,h.scale.y=k.worldScaleY,h.rotation=-(e.bone.worldRotation*Math.PI/180)}else h.visible=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.Spine.prototype.createSprite=function(a,b){var c=f.TextureCache[b.name]?b.name:b.name+".png",d=new f.Sprite(f.Texture.fromFrame(c));return d.scale=b.scale,d.rotation=b.rotation,d.anchor.x=d.anchor.y=.5,a.sprites=a.sprites||{},a.sprites[b.name]=d,d};var n={};n.BoneData=function(a,b){this.name=a,this.parent=b},n.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},n.SlotData=function(a,b){this.name=a,this.boneData=b},n.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},n.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},n.Bone.yDown=!1,n.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(a,b){var c=this.parent;null!=c?(this.worldX=this.x*c.m00+this.y*c.m01+c.worldX,this.worldY=this.x*c.m10+this.y*c.m11+c.worldY,this.worldScaleX=c.worldScaleX*this.scaleX,this.worldScaleY=c.worldScaleY*this.scaleY,this.worldRotation=c.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var d=this.worldRotation*Math.PI/180,e=Math.cos(d),f=Math.sin(d);this.m00=e*this.worldScaleX,this.m10=f*this.worldScaleX,this.m01=-f*this.worldScaleY,this.m11=e*this.worldScaleY,a&&(this.m00=-this.m00,this.m01=-this.m01),b&&(this.m10=-this.m10,this.m11=-this.m11),n.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var a=this.data;this.x=a.x,this.y=a.y,this.rotation=a.rotation,this.scaleX=a.scaleX,this.scaleY=a.scaleY}},n.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},n.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(a){this.attachment=a,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(a){this._attachmentTime=this.skeleton.time-a},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var a=this.data;this.r=a.r,this.g=a.g,this.b=a.b,this.a=a.a;for(var b=this.skeleton.data.slots,c=0,d=b.length;d>c;c++)if(b[c]==a){this.setAttachment(a.attachmentName?this.skeleton.getAttachmentBySlotIndex(c,a.attachmentName):null);break}}},n.Skin=function(a){this.name=a,this.attachments={}},n.Skin.prototype={addAttachment:function(a,b,c){this.attachments[a+":"+b]=c},getAttachment:function(a,b){return this.attachments[a+":"+b]},_attachAll:function(a,b){for(var c in b.attachments){var d=c.indexOf(":"),e=parseInt(c.substring(0,d)),f=c.substring(d+1),g=a.slots[e];if(g.attachment&&g.attachment.name==f){var h=this.getAttachment(e,f);h&&g.setAttachment(h)}}}},n.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},n.Animation.prototype={apply:function(a,b,c){c&&0!=this.duration&&(b%=this.duration);for(var d=this.timelines,e=0,f=d.length;f>e;e++)d[e].apply(a,b,1)},mix:function(a,b,c,d){c&&0!=this.duration&&(b%=this.duration);for(var e=this.timelines,f=0,g=e.length;g>f;f++)e[f].apply(a,b,d)}},n.binarySearch=function(a,b,c){var d=0,e=Math.floor(a.length/c)-2;if(0==e)return c;for(var f=e>>>1;;){if(a[(f+1)*c]<=b?d=f+1:e=f,d==e)return(d+1)*c;f=d+e>>>1}},n.linearSearch=function(a,b,c){for(var d=0,e=a.length-c;e>=d;d+=c)if(a[d]>b)return d;return-1},n.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},n.Curves.prototype={setLinear:function(a){this.curves[6*a]=0},setStepped:function(a){this.curves[6*a]=-1},setCurve:function(a,b,c,d,e){var f=.1,g=f*f,h=g*f,i=3*f,j=3*g,k=6*g,l=6*h,m=2*-b+d,n=2*-c+e,o=3*(b-d)+1,p=3*(c-e)+1,q=6*a,r=this.curves;r[q]=b*i+m*j+o*h,r[q+1]=c*i+n*j+p*h,r[q+2]=m*k+o*l,r[q+3]=n*k+p*l,r[q+4]=o*l,r[q+5]=p*l},getCurvePercent:function(a,b){b=0>b?0:b>1?1:b;var c=6*a,d=this.curves,e=d[c];if(!e)return b;if(-1==e)return 0;for(var f=d[c+1],g=d[c+2],h=d[c+3],i=d[c+4],j=d[c+5],k=e,l=f,m=8;;){if(k>=b){var n=k-e,o=l-f;return o+(l-o)*(b-n)/(k-n)}if(0==m)break;m--,e+=g,f+=h,g+=i,h+=j,k+=e,l+=f}return l+(1-l)*(b-k)/(1-k)}},n.RotateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=2*a},n.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(a,b,c){a*=2,this.frames[a]=b,this.frames[a+1]=c},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-2]){for(var f=e.data.rotation+d[d.length-1]-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;return e.rotation+=f*c,void 0}var g=n.binarySearch(d,b,2),h=d[g-1],i=d[g],j=1-(b-i)/(d[g-2]-i);j=this.curves.getCurvePercent(g/2-1,j);for(var f=d[g+1]-h;f>180;)f-=360;for(;-180>f;)f+=360;for(f=e.data.rotation+(h+f*j)-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;e.rotation+=f*c}}},n.TranslateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.x+=(e.data.x+d[d.length-2]-e.x)*c,e.y+=(e.data.y+d[d.length-1]-e.y)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.x+=(e.data.x+g+(d[f+1]-g)*j-e.x)*c,e.y+=(e.data.y+h+(d[f+2]-h)*j-e.y)*c}}},n.ScaleTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.scaleX+=(e.data.scaleX-1+d[d.length-2]-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+d[d.length-1]-e.scaleY)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.scaleX+=(e.data.scaleX-1+g+(d[f+1]-g)*j-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+h+(d[f+2]-h)*j-e.scaleY)*c}}},n.ColorTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=5*a},n.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(c,d){c*=5,this.frames[c]=d,this.frames[c+1]=r,this.frames[c+2]=g,this.frames[c+3]=b,this.frames[c+4]=a},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-5]){var f=d.length-1;return e.r=d[f-3],e.g=d[f-2],e.b=d[f-1],e.a=d[f],void 0}var g=n.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],l=d[g],m=1-(b-l)/(d[g-5]-l);m=this.curves.getCurvePercent(g/5-1,m);var o=h+(d[g+1]-h)*m,p=i+(d[g+2]-i)*m,q=j+(d[g+3]-j)*m,r=k+(d[g+4]-k)*m;1>c?(e.r+=(o-e.r)*c,e.g+=(p-e.g)*c,e.b+=(q-e.b)*c,e.a+=(r-e.a)*c):(e.r=o,e.g=p,e.b=q,e.a=r)}}},n.AttachmentTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},n.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(a,b,c){this.frames[a]=b,this.attachmentNames[a]=c},apply:function(a,b){var c=this.frames;if(!(b=c[c.length-1]?c.length-1:n.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},n.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},n.SkeletonData.prototype={defaultSkin:null,findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return slot[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSkin:function(a){for(var b=this.skins,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findAnimation:function(a){for(var b=this.animations,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null}},n.Skeleton=function(a){this.data=a,this.bones=[];for(var b=0,c=a.bones.length;c>b;b++){var d=a.bones[b],e=d.parent?this.bones[a.bones.indexOf(d.parent)]:null;this.bones.push(new n.Bone(d,e))}this.slots=[],this.drawOrder=[];for(var b=0,c=a.slots.length;c>b;b++){var f=a.slots[b],g=this.bones[a.bones.indexOf(f.boneData)],h=new n.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},n.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var a=this.flipX,b=this.flipY,c=this.bones,d=0,e=c.length;e>d;d++)c[d].updateWorldTransform(a,b)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var a=this.bones,b=0,c=a.length;c>b;b++)a[b].setToSetupPose()},setSlotsToSetupPose:function(){for(var a=this.slots,b=0,c=a.length;c>b;b++)a[b].setToSetupPose(b)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},setSkinByName:function(a){var b=this.data.findSkin(a); +if(!b)throw"Skin not found: "+a;this.setSkin(b)},setSkin:function(a){this.skin&&a&&a._attachAll(this,this.skin),this.skin=a},getAttachmentBySlotName:function(a,b){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(a),b)},getAttachmentBySlotIndex:function(a,b){if(this.skin){var c=this.skin.getAttachment(a,b);if(c)return c}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(a,b):null},setAttachment:function(a,b){for(var c=this.slots,d=0,e=c.size;e>d;d++){var f=c[d];if(f.data.name==a){var g=null;if(b&&(g=this.getAttachment(d,b),null==g))throw"Attachment not found: "+b+", for slot: "+a;return f.setAttachment(g),void 0}}throw"Slot not found: "+a},update:function(a){time+=a}},n.AttachmentType={region:0},n.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},n.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(a,b,c,d,e){var f=this.uvs;e?(f[2]=a,f[3]=d,f[4]=a,f[5]=b,f[6]=c,f[7]=b,f[0]=c,f[1]=d):(f[0]=a,f[1]=d,f[2]=a,f[3]=b,f[4]=c,f[5]=b,f[6]=c,f[7]=d)},updateOffset:function(){var a=this.width/this.regionOriginalWidth*this.scaleX,b=this.height/this.regionOriginalHeight*this.scaleY,c=-this.width/2*this.scaleX+this.regionOffsetX*a,d=-this.height/2*this.scaleY+this.regionOffsetY*b,e=c+this.regionWidth*a,f=d+this.regionHeight*b,g=this.rotation*Math.PI/180,h=Math.cos(g),i=Math.sin(g),j=c*h+this.x,k=c*i,l=d*h+this.y,m=d*i,n=e*h+this.x,o=e*i,p=f*h+this.y,q=f*i,r=this.offset;r[0]=j-m,r[1]=l+k,r[2]=j-q,r[3]=p+k,r[4]=n-q,r[5]=p+o,r[6]=n-m,r[7]=l+o},computeVertices:function(a,b,c,d){a+=c.worldX,b+=c.worldY;var e=c.m00,f=c.m01,g=c.m10,h=c.m11,i=this.offset;d[0]=i[0]*e+i[1]*f+a,d[1]=i[0]*g+i[1]*h+b,d[2]=i[2]*e+i[3]*f+a,d[3]=i[2]*g+i[3]*h+b,d[4]=i[4]*e+i[5]*f+a,d[5]=i[4]*g+i[5]*h+b,d[6]=i[6]*e+i[7]*f+a,d[7]=i[6]*g+i[7]*h+b}},n.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},n.AnimationStateData.prototype={defaultMix:0,setMixByName:function(a,b,c){var d=this.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;var e=this.skeletonData.findAnimation(b);if(!e)throw"Animation not found: "+b;this.setMix(d,e,c)},setMix:function(a,b,c){this.animationToMixTime[a.name+":"+b.name]=c},getMix:function(a,b){var c=this.animationToMixTime[a.name+":"+b.name];return c?c:this.defaultMix}},n.AnimationState=function(a){this.data=a,this.queue=[]},n.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(a){if(this.currentTime+=a,this.previousTime+=a,this.mixTime+=a,this.queue.length>0){var b=this.queue[0];this.currentTime>=b.delay&&(this._setAnimation(b.animation,b.loop),this.queue.shift())}},apply:function(a){if(this.current)if(this.previous){this.previous.apply(a,this.previousTime,this.previousLoop);var b=this.mixTime/this.mixDuration;b>=1&&(b=1,this.previous=null),this.current.mix(a,this.currentTime,this.currentLoop,b)}else this.current.apply(a,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(a,b){this.previous=null,a&&this.current&&(this.mixDuration=this.data.getMix(this.current,a),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=a,this.currentLoop=b,this.currentTime=0},setAnimationByName:function(a,b){var c=this.data.skeletonData.findAnimation(a);if(!c)throw"Animation not found: "+a;this.setAnimation(c,b)},setAnimation:function(a,b){this.queue.length=0,this._setAnimation(a,b)},addAnimationByName:function(a,b,c){var d=this.data.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;this.addAnimation(d,b,c)},addAnimation:function(a,b,c){var d={};if(d.animation=a,d.loop=b,!c||0>=c){var e=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;c=null!=e?e.duration-this.data.getMix(e,a)+(c||0):0}d.delay=c,this.queue.push(d)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},n.SkeletonJson=function(a){this.attachmentLoader=a},n.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new n.SkeletonData,c=a.bones,d=0,e=c.length;e>d;d++){var f=c[d],g=null;if(f.parent&&(g=b.findBone(f.parent),!g))throw"Parent bone not found: "+f.parent;var h=new n.BoneData(f.name,g);h.length=(f.length||0)*this.scale,h.x=(f.x||0)*this.scale,h.y=(f.y||0)*this.scale,h.rotation=f.rotation||0,h.scaleX=f.scaleX||1,h.scaleY=f.scaleY||1,b.bones.push(h)}for(var i=a.slots,d=0,e=i.length;e>d;d++){var j=i[d],h=b.findBone(j.bone);if(!h)throw"Slot bone not found: "+j.bone;var k=new n.SlotData(j.name,h),l=j.color;l&&(k.r=n.SkeletonJson.toColor(l,0),k.g=n.SkeletonJson.toColor(l,1),k.b=n.SkeletonJson.toColor(l,2),k.a=n.SkeletonJson.toColor(l,3)),k.attachmentName=j.attachment,b.slots.push(k)}var m=a.skins;for(var o in m)if(m.hasOwnProperty(o)){var p=m[o],q=new n.Skin(o);for(var r in p)if(p.hasOwnProperty(r)){var s=b.findSlotIndex(r),t=p[r];for(var u in t)if(t.hasOwnProperty(u)){var v=this.readAttachment(q,u,t[u]);null!=v&&q.addAttachment(s,u,v)}}b.skins.push(q),"default"==q.name&&(b.defaultSkin=q)}var w=a.animations;for(var x in w)w.hasOwnProperty(x)&&this.readAnimation(x,w[x],b);return b},readAttachment:function(a,b,c){b=c.name||b;var d=n.AttachmentType[c.type||"region"];if(d==n.AttachmentType.region){var e=new n.RegionAttachment;return e.x=(c.x||0)*this.scale,e.y=(c.y||0)*this.scale,e.scaleX=c.scaleX||1,e.scaleY=c.scaleY||1,e.rotation=c.rotation||0,e.width=(c.width||32)*this.scale,e.height=(c.height||32)*this.scale,e.updateOffset(),e.rendererObject={},e.rendererObject.name=b,e.rendererObject.scale={},e.rendererObject.scale.x=e.scaleX,e.rendererObject.scale.y=e.scaleY,e.rendererObject.rotation=-e.rotation*Math.PI/180,e}throw"Unknown attachment type: "+d},readAnimation:function(a,b,c){var d=[],e=0,f=b.bones;for(var g in f)if(f.hasOwnProperty(g)){var h=c.findBoneIndex(g);if(-1==h)throw"Bone not found: "+g;var i=f[g];for(var j in i)if(i.hasOwnProperty(j)){var k=i[j];if("rotate"==j){var l=new n.RotateTimeline(k.length);l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m,q.time,q.angle),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[2*l.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var l,r=1;"scale"==j?l=new n.ScaleTimeline(k.length):(l=new n.TranslateTimeline(k.length),r=this.scale),l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;l.setFrame(m,q.time,s,t),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[3*l.getFrameCount()-3])}}}var u=b.slots;for(var v in u)if(u.hasOwnProperty(v)){var w=u[v],x=c.findSlotIndex(v);for(var j in w)if(w.hasOwnProperty(j)){var k=w[j];if("color"==j){var l=new n.ColorTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=n.SkeletonJson.toColor(y,0),A=n.SkeletonJson.toColor(y,1),B=n.SkeletonJson.toColor(y,2),C=n.SkeletonJson.toColor(y,3);l.setFrame(m,q.time,z,A,B,C),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[5*l.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var l=new n.AttachmentTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m++,q.time,q.name)}d.push(l),e=Math.max(e,l.frames[l.getFrameCount()-1])}}}c.animations.push(new n.Animation(a,d,e))}},n.SkeletonJson.readCurve=function(a,b,c){var d=c.curve;d&&("stepped"==d?a.curves.setStepped(b):d instanceof Array&&a.curves.setCurve(b,d[0],d[1],d[2],d[3]))},n.SkeletonJson.toColor=function(a,b){if(8!=a.length)throw"Color hexidecimal length must be 8, recieved: "+a;return parseInt(a.substring(2*b,2),16)/255},n.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new n.AtlasReader(a),d=[];d.length=4;for(var e=null;;){var f=c.readLine();if(null==f)break;if(f=c.trim(f),0==f.length)e=null;else if(e){var g=new n.AtlasRegion;g.name=f,g.page=e,g.rotate="true"==c.readValue(),c.readTuple(d);var h=parseInt(d[0]),i=parseInt(d[1]);c.readTuple(d);var j=parseInt(d[0]),k=parseInt(d[1]);g.u=h/e.width,g.v=i/e.height,g.rotate?(g.u2=(h+k)/e.width,g.v2=(i+j)/e.height):(g.u2=(h+j)/e.width,g.v2=(i+k)/e.height),g.x=h,g.y=i,g.width=Math.abs(j),g.height=Math.abs(k),4==c.readTuple(d)&&(g.splits=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],4==c.readTuple(d)&&(g.pads=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],c.readTuple(d))),g.originalWidth=parseInt(d[0]),g.originalHeight=parseInt(d[1]),c.readTuple(d),g.offsetX=parseInt(d[0]),g.offsetY=parseInt(d[1]),g.index=parseInt(c.readValue()),this.regions.push(g)}else{e=new n.AtlasPage,e.name=f,e.format=n.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=n.Atlas.TextureFilter[d[0]],e.magFilter=n.Atlas.TextureFilter[d[1]];var l=c.readValue();e.uWrap=n.Atlas.TextureWrap.clampToEdge,e.vWrap=n.Atlas.TextureWrap.clampToEdge,"x"==l?e.uWrap=n.Atlas.TextureWrap.repeat:"y"==l?e.vWrap=n.Atlas.TextureWrap.repeat:"xy"==l&&(e.uWrap=e.vWrap=n.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},n.Atlas.prototype={findRegion:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},dispose:function(){for(var a=this.pages,b=0,c=a.length;c>b;b++)this.textureLoader.unload(a[b].rendererObject)},updateUVs:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++){var e=b[c];e.page==a&&(e.u=e.x/a.width,e.v=e.y/a.height,e.rotate?(e.u2=(e.x+e.height)/a.width,e.v2=(e.y+e.width)/a.height):(e.u2=(e.x+e.width)/a.width,e.v2=(e.y+e.height)/a.height))}}},n.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},n.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},n.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},n.AtlasPage=function(){},n.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},n.AtlasRegion=function(){},n.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},n.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},n.AtlasReader.prototype={index:0,trim:function(a){return a.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var a=this.readLine(),b=a.indexOf(":");if(-1==b)throw"Invalid line: "+a;return this.trim(a.substring(b+1))},readTuple:function(a){var b=this.readLine(),c=b.indexOf(":");if(-1==c)throw"Invalid line: "+b;for(var d=0,e=c+1;3>d;d++){var f=b.indexOf(",",e);if(-1==f){if(0==d)throw"Invalid line: "+b;break}a[d]=this.trim(b.substr(e,f-e)),e=f+1}return a[d]=this.trim(b.substring(e)),d+1}},n.AtlasAttachmentLoader=function(a){this.atlas=a},n.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case n.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new n.RegionAttachment(c);return e.rendererObject=d,e.setUVs(d.u,d.v,d.u2,d.v2,d.rotate),e.regionOffsetX=d.offsetX,e.regionOffsetY=d.offsetY,e.regionWidth=d.width,e.regionHeight=d.height,e.regionOriginalWidth=d.originalWidth,e.regionOriginalHeight=d.originalHeight,e}throw"Unknown attachment type: "+b}},f.AnimCache={},n.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this),this.renderable=!0},f.CustomRenderable.prototype=Object.create(f.DisplayObject.prototype),f.CustomRenderable.prototype.constructor=f.CustomRenderable,f.CustomRenderable.prototype.renderCanvas=function(){},f.CustomRenderable.prototype.initWebGL=function(){},f.CustomRenderable.prototype.renderWebGL=function(){},f.BaseTextureCache={},f.texturesToUpdate=[],f.texturesToDestroy=[],f.BaseTexture=function(a){if(f.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=a,a){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);else{var b=this;this.source.onload=function(){b.hasLoaded=!0,b.width=b.source.width,b.height=b.source.height,f.texturesToUpdate.push(b),b.dispatchEvent({type:"loaded",content:b})}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);this._powerOf2=!1}},f.BaseTexture.prototype.constructor=f.BaseTexture,f.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,f.texturesToDestroy.push(this)},f.BaseTexture.fromImage=function(a,b){var c=f.BaseTextureCache[a];if(!c){var d=new Image;b&&(d.crossOrigin=""),d.src=a,c=new f.BaseTexture(d),f.BaseTextureCache[a]=c}return c},f.TextureCache={},f.FrameCache={},f.Texture=function(a,b){if(f.EventTarget.call(this),b||(this.noFrame=!0,b=new f.Rectangle(0,0,1,1)),a instanceof f.Texture&&(a=a.baseTexture),this.baseTexture=a,this.frame=b,this.trim=new f.Point,this.scope=this,a.hasLoaded)this.noFrame&&(b=new f.Rectangle(0,0,a.width,a.height)),this.setFrame(b);else{var c=this;a.addEventListener("loaded",function(){c.onBaseTextureLoaded()})}},f.Texture.prototype.constructor=f.Texture,f.Texture.prototype.onBaseTextureLoaded=function(){var a=this.baseTexture;a.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new f.Rectangle(0,0,a.width,a.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},f.Texture.prototype.destroy=function(a){a&&this.baseTexture.destroy()},f.Texture.prototype.setFrame=function(a){if(this.frame=a,this.width=a.width,this.height=a.height,a.x+a.width>this.baseTexture.width||a.y+a.height>this.baseTexture.height)throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,f.Texture.frameUpdates.push(this)},f.Texture.fromImage=function(a,b){var c=f.TextureCache[a];return c||(c=new f.Texture(f.BaseTexture.fromImage(a,b)),f.TextureCache[a]=c),c},f.Texture.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache "+this);return b},f.Texture.fromCanvas=function(a){var b=new f.BaseTexture(a);return new f.Texture(b)},f.Texture.addTextureToCache=function(a,b){f.TextureCache[b]=a},f.Texture.removeTextureFromCache=function(a){var b=f.TextureCache[a];return f.TextureCache[a]=null,b},f.Texture.frameUpdates=[],f.RenderTexture=function(a,b){f.EventTarget.call(this),this.width=a||100,this.height=b||100,this.indetityMatrix=f.mat3.create(),this.frame=new f.Rectangle(0,0,this.width,this.height),f.gl?this.initWebGL():this.initCanvas()},f.RenderTexture.prototype=Object.create(f.Texture.prototype),f.RenderTexture.prototype.constructor=f.RenderTexture,f.RenderTexture.prototype.initWebGL=function(){var a=f.gl;this.glFramebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new f.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.baseTexture._glTexture),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,this.width,this.height,0,a.RGBA,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new f.Point(this.width/2,-this.height/2),this.render=this.renderWebGL},f.RenderTexture.prototype.resize=function(a,b){if(this.width=a,this.height=b,f.gl){this.projection.x=this.width/2,this.projection.y=-this.height/2;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.baseTexture._glTexture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,this.width,this.height,0,c.RGBA,c.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height)},f.RenderTexture.prototype.initCanvas=function(){this.renderer=new f.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new f.BaseTexture(this.renderer.view),this.frame=new f.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},f.RenderTexture.prototype.renderWebGL=function(a,b,c){var d=f.gl;d.colorMask(!0,!0,!0,!0),d.viewport(0,0,this.width,this.height),d.bindFramebuffer(d.FRAMEBUFFER,this.glFramebuffer),c&&(d.clearColor(0,0,0,0),d.clear(d.COLOR_BUFFER_BIT));var e=a.children,g=a.worldTransform;a.worldTransform=f.mat3.create(),a.worldTransform[4]=-1,a.worldTransform[5]=-2*this.projection.y,b&&(a.worldTransform[2]=b.x,a.worldTransform[5]-=b.y),f.visibleCount++,a.vcount=f.visibleCount;for(var h=0,i=e.length;i>h;h++)e[h].updateTransform();var j=a.__renderGroup;j?a==j.root?j.render(this.projection,this.glFramebuffer):j.renderSpecific(a,this.projection,this.glFramebuffer):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection,this.glFramebuffer)),a.worldTransform=g},f.RenderTexture.prototype.renderCanvas=function(a,b,c){var d=a.children;a.worldTransform=f.mat3.create(),b&&(a.worldTransform[2]=b.x,a.worldTransform[5]=b.y);for(var e=0,g=d.length;g>e;e++)d[e].updateTransform();c&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(a),this.renderer.context.setTransform(1,0,0,1,0,0)},f.AssetLoader=function(a,b){f.EventTarget.call(this),this.assetURLs=a,this.crossorigin=b,this.loadersByType={jpg:f.ImageLoader,jpeg:f.ImageLoader,png:f.ImageLoader,gif:f.ImageLoader,json:f.JsonLoader,anim:f.SpineLoader,xml:f.BitmapFontLoader,fnt:f.BitmapFontLoader}},f.AssetLoader.prototype.constructor=f.AssetLoader,f.AssetLoader.prototype.load=function(){var a=this;this.loadCount=this.assetURLs.length;for(var b=0;bh;h++)for(var i=0;d>i;i++,g++){var j=new f.Texture(this.texture,{x:i*a,y:h*b,width:a,height:b});this.frames.push(j),c&&(f.TextureCache[c+"-"+g]=j)}if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var k=this;this.texture.baseTexture.addEventListener("loaded",function(){k.onLoaded()})}},f.BitmapFontLoader=function(a,b){f.EventTarget.call(this),this.url=a,this.crossorigin=b,this.baseUrl=a.replace(/[^\/]*$/,""),this.texture=null},f.BitmapFontLoader.prototype.constructor=f.BitmapFontLoader,f.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var a=this;this.ajaxRequest.onreadystatechange=function(){a.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},f.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var a=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,b=new f.ImageLoader(a,this.crossorigin);this.texture=b.texture.baseTexture;var c={},d=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],e=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];c.font=d.attributes.getNamedItem("face").nodeValue,c.size=parseInt(d.attributes.getNamedItem("size").nodeValue,10),c.lineHeight=parseInt(e.attributes.getNamedItem("lineHeight").nodeValue,10),c.chars={};for(var g=this.ajaxRequest.responseXML.getElementsByTagName("char"),h=0;h/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', - '<%= dirs.src %>/filters/GreyFilter.js', + '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', '<%= dirs.src %>/filters/PixelateFilter.js', '<%= dirs.src %>/filters/BlurXFilter.js', diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index 21b0257..1e11684 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1,12289 +1,12548 @@ /** + * @license + * Pixi.JS - v1.3.0 + * Copyright (c) 2012, Mat Groves + * http://goodboydigital.com/ + * + * Compiled: 2013-11-20 + * + * Pixi.JS is licensed under the MIT License. + * http://www.opensource.org/licenses/mit-license.php + */ +/** * @author Mat Groves http://matgroves.com/ @Doormat23 */ (function(){ var root = this; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * @module PIXI - */ -var PIXI = PIXI || {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point - * @param y {Number} position of the point - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -} - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -} - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -} - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - - -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -} - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -} - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; - -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayobjects - * - * @class Circle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -} - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -} - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - - -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayobjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse - * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall width of this ellipse - * @param height {Number} The overall height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -} - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -} - -/** - * Checks if the x, and y coords passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coord of the point to test - * @param y {Number} The Y coord of the point to test - * @return {Boolean} if the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - //and a radius of 0.5 - var normx = ((x - this.x) / this.width) - 0.5, - normy = ((y - this.y) / this.height) - 0.5; - - normx *= normx; - normy *= normy; - - return (normx + normy < 0.25); -} - -PIXI.Ellipse.getBounds = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - - - -/* - * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV - * you both rock! - */ - -function determineMatrixArrayType() { - PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; - return PIXI.Matrix; -} - -determineMatrixArrayType(); - -PIXI.mat3 = {}; - -PIXI.mat3.create = function() -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat3.identity = function(matrix) -{ - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - - return matrix; -} - - -PIXI.mat4 = {}; - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat3.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], - a10 = mat[3], a11 = mat[4], a12 = mat[5], - a20 = mat[6], a21 = mat[7], a22 = mat[8], - - b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], - b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], - b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - - dest[0] = b00 * a00 + b01 * a10 + b02 * a20; - dest[1] = b00 * a01 + b01 * a11 + b02 * a21; - dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - - dest[3] = b10 * a00 + b11 * a10 + b12 * a20; - dest[4] = b10 * a01 + b11 * a11 + b12 * a21; - dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - - dest[6] = b20 * a00 + b21 * a10 + b22 * a20; - dest[7] = b20 * a01 + b21 * a11 + b22 * a21; - dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - - return dest; -} - -PIXI.mat3.clone = function(mat) -{ - var matrix = new PIXI.Matrix(9); - - matrix[0] = mat[0]; - matrix[1] = mat[1]; - matrix[2] = mat[2]; - matrix[3] = mat[3]; - matrix[4] = mat[4]; - matrix[5] = mat[5]; - matrix[6] = mat[6]; - matrix[7] = mat[7]; - matrix[8] = mat[8]; - - return matrix; -} - -PIXI.mat3.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) { - var a01 = mat[1], a02 = mat[2], - a12 = mat[5]; - - mat[1] = mat[3]; - mat[2] = mat[6]; - mat[3] = a01; - mat[5] = mat[7]; - mat[6] = a02; - mat[7] = a12; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[3]; - dest[2] = mat[6]; - dest[3] = mat[1]; - dest[4] = mat[4]; - dest[5] = mat[7]; - dest[6] = mat[2]; - dest[7] = mat[5]; - dest[8] = mat[8]; - return dest; -} - -PIXI.mat3.toMat4 = function (mat, dest) -{ - if (!dest) { dest = PIXI.mat4.create(); } - - dest[15] = 1; - dest[14] = 0; - dest[13] = 0; - dest[12] = 0; - - dest[11] = 0; - dest[10] = mat[8]; - dest[9] = mat[7]; - dest[8] = mat[6]; - - dest[7] = 0; - dest[6] = mat[5]; - dest[5] = mat[4]; - dest[4] = mat[3]; - - dest[3] = 0; - dest[2] = mat[2]; - dest[1] = mat[1]; - dest[0] = mat[0]; - - return dest; -} - - -///// - - -PIXI.mat4.create = function() -{ - var matrix = new PIXI.Matrix(16); - - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 0; - matrix[5] = 1; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 0; - matrix[9] = 0; - matrix[10] = 1; - matrix[11] = 0; - matrix[12] = 0; - matrix[13] = 0; - matrix[14] = 0; - matrix[15] = 1; - - return matrix; -} - -PIXI.mat4.transpose = function (mat, dest) -{ - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) - { - var a01 = mat[1], a02 = mat[2], a03 = mat[3], - a12 = mat[6], a13 = mat[7], - a23 = mat[11]; - - mat[1] = mat[4]; - mat[2] = mat[8]; - mat[3] = mat[12]; - mat[4] = a01; - mat[6] = mat[9]; - mat[7] = mat[13]; - mat[8] = a02; - mat[9] = a12; - mat[11] = mat[14]; - mat[12] = a03; - mat[13] = a13; - mat[14] = a23; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[4]; - dest[2] = mat[8]; - dest[3] = mat[12]; - dest[4] = mat[1]; - dest[5] = mat[5]; - dest[6] = mat[9]; - dest[7] = mat[13]; - dest[8] = mat[2]; - dest[9] = mat[6]; - dest[10] = mat[10]; - dest[11] = mat[14]; - dest[12] = mat[3]; - dest[13] = mat[7]; - dest[14] = mat[11]; - dest[15] = mat[15]; - return dest; -} - -PIXI.mat4.multiply = function (mat, mat2, dest) -{ - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; - var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; - var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; - var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - - // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; - dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[4]; - b1 = mat2[5]; - b2 = mat2[6]; - b3 = mat2[7]; - dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[8]; - b1 = mat2[9]; - b2 = mat2[10]; - b3 = mat2[11]; - dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = mat2[12]; - b1 = mat2[13]; - b2 = mat2[14]; - b3 = mat2[15]; - dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - return dest; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The base class for all objects that are rendered on the screen. - * - * @class DisplayObject - * @constructor - */ -PIXI.DisplayObject = function() -{ - this.last = this; - this.first = this; - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @property position - * @type Point - */ - this.position = new PIXI.Point(); - - /** - * The scale factor of the object. - * - * @property scale - * @type Point - */ - this.scale = new PIXI.Point(1,1);//{x:1, y:1}; - - /** - * The pivot point of the displayObject that it rotates around - * - * @property pivot - * @type Point - */ - this.pivot = new PIXI.Point(0,0); - - /** - * The rotation of the object in radians. - * - * @property rotation - * @type Number - */ - this.rotation = 0; - - /** - * The opacity of the object. - * - * @property alpha - * @type Number - */ - this.alpha = 1; - - /** - * The visibility of the object. - * - * @property visible - * @type Boolean - */ - this.visible = true; - - /** - * This is the defined area that will pick up mouse / touch events. It is null by default. - * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) - * - * @property hitArea - * @type Rectangle|Circle|Ellipse|Polygon - */ - this.hitArea = null; - - /** - * This is used to indicate if the displayObject should display a mouse hand cursor on rollover - * - * @property buttonMode - * @type Boolean - */ - this.buttonMode = false; - - /** - * Can this object be rendered - * - * @property renderable - * @type Boolean - */ - this.renderable = false; - - /** - * [read-only] The display object container that contains this display object. - * - * @property parent - * @type DisplayObjectContainer - * @readOnly - */ - this.parent = null; - - /** - * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. - * - * @property stage - * @type Stage - * @readOnly - */ - this.stage = null; - - /** - * [read-only] The multiplied alpha of the displayobject - * - * @property worldAlpha - * @type Number - * @readOnly - */ - this.worldAlpha = 1; - - /** - * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property - * - * @property _interactive - * @type Boolean - * @readOnly - * @private - */ - this._interactive = false; - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [read-only] Current transform of the object locally - * - * @property localTransform - * @type Mat3 - * @readOnly - * @private - */ - this.localTransform = PIXI.mat3.create()//mat3.identity(); - - /** - * [NYI] Unkown - * - * @property color - * @type Array<> - * @private - */ - this.color = []; - - /** - * [NYI] Holds whether or not this object is dynamic, for rendering optimization - * - * @property dynamic - * @type Boolean - * @private - */ - this.dynamic = true; - - // chach that puppy! - this._sr = 0; - this._cr = 1; - - - this.filterArea = new PIXI.Rectangle(0,0,1,1); - - /* - * MOUSE Callbacks - */ - - /** - * A callback that is used when the users clicks on the displayObject with their mouse - * @method click - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user clicks the mouse down over the sprite - * @method mousedown - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject - * for this callback to be fired the mouse must have been pressed down over the displayObject - * @method mouseup - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject - * for this callback to be fired, The touch must have started over the displayObject - * @method mouseupoutside - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse rolls over the displayObject - * @method mouseover - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the users mouse leaves the displayObject - * @method mouseout - * @param interactionData {InteractionData} - */ - - - /* - * TOUCH Callbacks - */ - - /** - * A callback that is used when the users taps on the sprite with their finger - * basically a touch version of click - * @method tap - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user touch's over the displayObject - * @method touchstart - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases a touch over the displayObject - * @method touchend - * @param interactionData {InteractionData} - */ - - /** - * A callback that is used when the user releases the touch that was over the displayObject - * for this callback to be fired, The touch must have started over the sprite - * @method touchendoutside - * @param interactionData {InteractionData} - */ -} - -// constructor -PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; - -/** - * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default - * Instead of using this function you can now simply set the interactive property to true or false - * - * @method setInteractive - * @param interactive {Boolean} - * @deprecated Simply set the `interactive` property directly - */ -PIXI.DisplayObject.prototype.setInteractive = function(interactive) -{ - this.interactive = interactive; -} - -/** - * Indicates if the sprite will have touch and mouse interactivity. It is false by default - * - * @property interactive - * @type Boolean - * @default false - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { - get: function() { - return this._interactive; - }, - set: function(value) { - this._interactive = value; - - // TODO more to be done here.. - // need to sort out a re-crawl! - if(this.stage)this.stage.dirty = true; - } -}); - -/** - * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. - * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. - * To remove a mask, set this property to null. - * - * @property mask - * @type Graphics - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { - get: function() { - return this._mask; - }, - set: function(value) { - - - if(value) - { - if(this._mask) - { - value.start = this._mask.start; - value.end = this._mask.end; - } - else - { - this.addFilter(value); - value.renderable = false; - } - } - else - { - this.removeFilter(this._mask); - this._mask.renderable = true; - } - - this._mask = value; - } -}); - -/** - * Sets the filters for the displayObject. - * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. - * To remove filters simply set this property to 'null' - * @property filters - * @type Array An array of filters - */ -Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { - get: function() { - return this._filters; - }, - set: function(value) { - - if(value) - { - if(this._filters)this.removeFilter(this._filters); - this.addFilter(value); - - // now put all the passes in one place.. - var passes = []; - for (var i = 0; i < value.length; i++) - { - var filterPasses = value[i].passes; - for (var j = 0; j < filterPasses.length; j++) - { - passes.push(filterPasses[j]); - }; - }; - - value.start.filterPasses = passes; - } - else - { - if(this._filters)this.removeFilter(this._filters); - } - - this._filters = value; - - - - - } -}); - -/* - * Adds a filter to this displayObject - * - * @method addFilter - * @param mask {Graphics} the graphics object to use as a filter - * @private - */ -PIXI.DisplayObject.prototype.addFilter = function(data) -{ - //if(this.filter)return; - //this.filter = true; -// data[0].target = this; - - - // insert a filter block.. - // TODO Onject pool thease bad boys.. - var start = new PIXI.FilterBlock(); - var end = new PIXI.FilterBlock(); - - data.start = start; - data.end = end; - - start.data = data; - end.data = data; - - start.first = start.last = this; - end.first = end.last = this; - - start.open = true; - - start.target = this; - - /* - * insert start - */ - - var childFirst = start - var childLast = start - var nextObject; - var previousObject; - - previousObject = this.first._iPrev; - - if(previousObject) - { - nextObject = previousObject._iNext; - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - } - else - { - nextObject = this; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - - // now insert the end filter block.. - - /* - * insert end filter - */ - var childFirst = end - var childLast = end - var nextObject = null; - var previousObject = null; - - previousObject = this.last; - nextObject = previousObject._iNext; - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - var updateLast = this; - - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = end; - } - updateLast = updateLast.parent; - } - - this.first = start; - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.addFilterBlocks(start, end); - } - -} - -/* - * Removes the filter to this displayObject - * - * @method removeFilter - * @private - */ -PIXI.DisplayObject.prototype.removeFilter = function(data) -{ - //if(!this.filter)return; - //this.filter = false; - console.log("YUOIO") - // modify the list.. - var startBlock = data.start; - - - var nextObject = startBlock._iNext; - var previousObject = startBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - if(previousObject)previousObject._iNext = nextObject; - - this.first = startBlock._iNext; - - // remove the end filter - var lastBlock = data.end; - - var nextObject = lastBlock._iNext; - var previousObject = lastBlock._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - // this is always true too! - var tempLast = lastBlock._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == lastBlock) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); - } -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObject.prototype.updateTransform = function() -{ - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); - } - - var localTransform = this.localTransform; - var parentTransform = this.parent.worldTransform; - var worldTransform = this.worldTransform; - //console.log(localTransform) - localTransform[0] = this._cr * this.scale.x; - localTransform[1] = -this._sr * this.scale.y - localTransform[3] = this._sr * this.scale.x; - localTransform[4] = this._cr * this.scale.y; - - // TODO --> do we even need a local matrix??? - - var px = this.pivot.x; - var py = this.pivot.y; - - // Cache the matrix values (makes for huge speed increases!) - var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], - a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], - - b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], - b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; - - localTransform[2] = a02 - localTransform[5] = a12 - - worldTransform[0] = b00 * a00 + b01 * a10; - worldTransform[1] = b00 * a01 + b01 * a11; - worldTransform[2] = b00 * a02 + b01 * a12 + b02; - - worldTransform[3] = b10 * a00 + b11 * a10; - worldTransform[4] = b10 * a01 + b11 * a11; - worldTransform[5] = b10 * a02 + b11 * a12 + b12; - - // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! - // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); - this.worldAlpha = this.alpha * this.parent.worldAlpha; - - this.vcount = PIXI.visibleCount; - -} - -PIXI.visibleCount = 0; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A DisplayObjectContainer represents a collection of display objects. - * It is the base class of all display objects that act as a container for other objects. - * - * @class DisplayObjectContainer - * @extends DisplayObject - * @constructor - */ -PIXI.DisplayObjectContainer = function() -{ - PIXI.DisplayObject.call( this ); - - /** - * [read-only] The of children of this container. - * - * @property children - * @type Array - * @readOnly - */ - this.children = []; -} - -// constructor -PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; - -/** - * Adds a child to the container. - * - * @method addChild - * @param child {DisplayObject} The DisplayObject to add to the container - */ -PIXI.DisplayObjectContainer.prototype.addChild = function(child) -{ - if(child.parent != undefined) - { - - //// COULD BE THIS??? - child.parent.removeChild(child); - // return; - } - - child.parent = this; - - this.children.push(child); - - // update the stage refference.. - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // LINKED LIST // - - // modify the list.. - var childFirst = child.first - var childLast = child.last; - var nextObject; - var previousObject; - - // this could be wrong if there is a filter?? - if(this._filters || this._mask) - { - previousObject = this.last._iPrev; - } - else - { - previousObject = this.last; - } - - nextObject = previousObject._iNext; - - // always true in this case - // need to make sure the parents last is updated too - var updateLast = this; - var prevLast = previousObject; - - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - -} - -/** - * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown - * - * @method addChildAt - * @param child {DisplayObject} The child to add - * @param index {Number} The index to place the child in - */ -PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) -{ - if(index >= 0 && index <= this.children.length) - { - if(child.parent != undefined) - { - child.parent.removeChild(child); - } - child.parent = this; - - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = this.stage; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - var nextObject; - var previousObject; - - if(index == this.children.length) - { - previousObject = this.last; - var updateLast = this; - var prevLast = this.last; - while(updateLast) - { - if(updateLast.last == prevLast) - { - updateLast.last = child.last; - } - updateLast = updateLast.parent; - } - } - else if(index == 0) - { - previousObject = this; - } - else - { - previousObject = this.children[index-1].last; - } - - nextObject = previousObject._iNext; - - // always true in this case - if(nextObject) - { - nextObject._iPrev = childLast; - childLast._iNext = nextObject; - } - - childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - - this.children.splice(index, 0, child); - // need to remove any render groups.. - if(this.__renderGroup) - { - // being used by a renderTexture.. if it exists then it must be from a render texture; - if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); - // add them to the new render group.. - this.__renderGroup.addDisplayObjectAndChildren(child); - } - - } - else - { - throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); - } -} - -/** - * [NYI] Swaps the depth of 2 displayObjects - * - * @method swapChildren - * @param child {DisplayObject} - * @param child2 {DisplayObject} - * @private - */ -PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) -{ - /* - * this funtion needs to be recoded.. - * can be done a lot faster.. - */ - return; - - // need to fix this function :/ - /* - // TODO I already know this?? - var index = this.children.indexOf( child ); - var index2 = this.children.indexOf( child2 ); - - if ( index !== -1 && index2 !== -1 ) - { - // cool - - /* - if(this.stage) - { - // this is to satisfy the webGL batching.. - // TODO sure there is a nicer way to achieve this! - this.stage.__removeChild(child); - this.stage.__removeChild(child2); - - this.stage.__addChild(child); - this.stage.__addChild(child2); - } - - // swap the positions.. - this.children[index] = child2; - this.children[index2] = child; - - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - }*/ -} - -/** - * Returns the Child at the specified index - * - * @method getChildAt - * @param index {Number} The index to get the child from - */ -PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) -{ - if(index >= 0 && index < this.children.length) - { - return this.children[index]; - } - else - { - throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); - } -} - -/** - * Removes a child from the container. - * - * @method removeChild - * @param child {DisplayObject} The DisplayObject to remove - */ -PIXI.DisplayObjectContainer.prototype.removeChild = function(child) -{ - var index = this.children.indexOf( child ); - if ( index !== -1 ) - { - // unlink // - // modify the list.. - var childFirst = child.first; - var childLast = child.last; - - var nextObject = childLast._iNext; - var previousObject = childFirst._iPrev; - - if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - - if(this.last == childLast) - { - var tempLast = childFirst._iPrev; - // need to make sure the parents last is updated too - var updateLast = this; - while(updateLast.last == childLast.last) - { - updateLast.last = tempLast; - updateLast = updateLast.parent; - if(!updateLast)break; - } - } - - childLast._iNext = null; - childFirst._iPrev = null; - - // update the stage reference.. - if(this.stage) - { - var tmpChild = child; - do - { - if(tmpChild.interactive)this.stage.dirty = true; - tmpChild.stage = null; - tmpChild = tmpChild._iNext; - } - while(tmpChild) - } - - // webGL trim - if(child.__renderGroup) - { - child.__renderGroup.removeDisplayObjectAndChildren(child); - } - - child.parent = undefined; - this.children.splice( index, 1 ); - } - else - { - throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); - } -} - -/* - * Updates the container's children's transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.DisplayObjectContainer.prototype.updateTransform = function() -{ - if(!this.visible)return; - - PIXI.DisplayObject.prototype.updateTransform.call( this ); - - for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation - */ -PIXI.MovieClip = function(textures) -{ - PIXI.Sprite.call(this, textures[0]); - - /** - * The array of textures that make up the animation - * - * @property textures - * @type Array - */ - this.textures = textures; - - /** - * The speed that the MovieClip will play at. Higher is faster, lower is slower - * - * @property animationSpeed - * @type Number - * @default 1 - */ - this.animationSpeed = 1; - - /** - * Whether or not the movie clip repeats after playing. - * - * @property loop - * @type Boolean - * @default true - */ - this.loop = true; - - /** - * Function to call when a MovieClip finishes playing - * - * @property onComplete - * @type Function - */ - this.onComplete = null; - - /** - * [read-only] The index MovieClips current frame (this may not have to be a whole number) - * - * @property currentFrame - * @type Number - * @default 0 - * @readOnly - */ - this.currentFrame = 0; - - /** - * [read-only] Indicates if the MovieClip is currently playing - * - * @property playing - * @type Boolean - * @readOnly - */ - this.playing = false; -} - -// constructor -PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); -PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; - -/** -* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures -* assigned to the MovieClip. -* -* @property totalFrames -* @type Number -* @default 0 -* @readOnly -*/ -Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { - get: function() { - - return this.textures.length; - } -}); - - -/** - * Stops the MovieClip - * - * @method stop - */ -PIXI.MovieClip.prototype.stop = function() -{ - this.playing = false; -} - -/** - * Plays the MovieClip - * - * @method play - */ -PIXI.MovieClip.prototype.play = function() -{ - this.playing = true; -} - -/** - * Stops the MovieClip and goes to a specific frame - * - * @method gotoAndStop - * @param frameNumber {Number} frame index to stop at - */ -PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) -{ - this.playing = false; - this.currentFrame = frameNumber; - var round = (this.currentFrame + 0.5) | 0; - this.setTexture(this.textures[round % this.textures.length]); -} - -/** - * Goes to a specific frame and begins playing the MovieClip - * - * @method gotoAndPlay - * @param frameNumber {Number} frame index to start at - */ -PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) -{ - this.currentFrame = frameNumber; - this.playing = true; -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.MovieClip.prototype.updateTransform = function() -{ - PIXI.Sprite.prototype.updateTransform.call(this); - - if(!this.playing)return; - - this.currentFrame += this.animationSpeed; - - var round = (this.currentFrame + 0.5) | 0; - - if(this.loop || round < this.textures.length) - { - this.setTexture(this.textures[round % this.textures.length]); - } - else if(round >= this.textures.length) - { - this.gotoAndStop(this.textures.length - 1); - if(this.onComplete) - { - this.onComplete(); - } - } -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - - -PIXI.FilterBlock = function() -{ - this.visible = true; - this.renderable = true; -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text to split a line you can use "\n" - * - * @class Text - * @extends Sprite - * @constructor - * @param text {String} The copy that you would like the text to display - * @param [style] {Object} The style parameters - * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text = function(text, style) -{ - this.canvas = document.createElement("canvas"); - this.context = this.canvas.getContext("2d"); - PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); - - this.setText(text); - this.setStyle(style); - - this.updateText(); - this.dirty = false; -}; - -// constructor -PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); -PIXI.Text.prototype.constructor = PIXI.Text; - -/** - * Set the style of the text - * - * @method setStyle - * @param [style] {Object} The style parameters - * @param [style.font="bold 20pt Arial"] {String} The style and size of the font - * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" - * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap - */ -PIXI.Text.prototype.setStyle = function(style) -{ - style = style || {}; - style.font = style.font || "bold 20pt Arial"; - style.fill = style.fill || "black"; - style.align = style.align || "left"; - style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 - style.strokeThickness = style.strokeThickness || 0; - style.wordWrap = style.wordWrap || false; - style.wordWrapWidth = style.wordWrapWidth || 100; - this.style = style; - this.dirty = true; -}; - -/** - * Set the copy for the text object. To split a line you can use "\n" - * - * @methos setText - * @param {String} text The copy that you would like the text to display - */ -PIXI.Text.prototype.setText = function(text) -{ - this.text = text.toString() || " "; - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.Text.prototype.updateText = function() -{ - this.context.font = this.style.font; - - var outputText = this.text; - - // word wrap - // preserve original text - if(this.style.wordWrap)outputText = this.wordWrap(this.text); - - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - //calculate text width - var lineWidths = []; - var maxLineWidth = 0; - for (var i = 0; i < lines.length; i++) - { - var lineWidth = this.context.measureText(lines[i]).width; - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - this.canvas.width = maxLineWidth + this.style.strokeThickness; - - //calculate text height - var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; - this.canvas.height = lineHeight * lines.length; - - //set canvas text styles - this.context.fillStyle = this.style.fill; - this.context.font = this.style.font; - - this.context.strokeStyle = this.style.stroke; - this.context.lineWidth = this.style.strokeThickness; - - this.context.textBaseline = "top"; - - //draw lines line by line - for (i = 0; i < lines.length; i++) - { - var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - - if(this.style.align == "right") - { - linePosition.x += maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - linePosition.x += (maxLineWidth - lineWidths[i]) / 2; - } - - if(this.style.stroke && this.style.strokeThickness) - { - this.context.strokeText(lines[i], linePosition.x, linePosition.y); - } - - if(this.style.fill) - { - this.context.fillText(lines[i], linePosition.x, linePosition.y); - } - } - - this.updateTexture(); -}; - -/** - * Updates texture size based on canvas size - * - * @method updateTexture - * @private - */ -PIXI.Text.prototype.updateTexture = function() -{ - this.texture.baseTexture.width = this.canvas.width; - this.texture.baseTexture.height = this.canvas.height; - this.texture.frame.width = this.canvas.width; - this.texture.frame.height = this.canvas.height; - - this._width = this.canvas.width; - this._height = this.canvas.height; - - PIXI.texturesToUpdate.push(this.texture.baseTexture); -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.Text.prototype.updateTransform = function() -{ - if(this.dirty) - { - this.updateText(); - this.dirty = false; - } - - PIXI.Sprite.prototype.updateTransform.call(this); -}; - -/* - * http://stackoverflow.com/users/34441/ellisbben - * great solution to the problem! - * - * @method determineFontHeight - * @param fontStyle {Object} - * @private - */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) -{ - // build a little reference dictionary so if the font style has been used return a - // cached version... - var result = PIXI.Text.heightCache[fontStyle]; - - if(!result) - { - var body = document.getElementsByTagName("body")[0]; - var dummy = document.createElement("div"); - var dummyText = document.createTextNode("M"); - dummy.appendChild(dummyText); - dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); - body.appendChild(dummy); - - result = dummy.offsetHeight; - PIXI.Text.heightCache[fontStyle] = result; - - body.removeChild(dummy); - } - - return result; -}; - -/** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. - * - * @method wordWrap - * @param text {String} - * @private - */ -PIXI.Text.prototype.wordWrap = function(text) -{ - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ""; - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) - { - var spaceLeft = this.style.wordWrapWidth; - var words = lines[i].split(" "); - for (var j = 0; j < words.length; j++) - { - var wordWidth = this.context.measureText(words[j]).width; - var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; - if(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 = this.style.wordWrapWidth - wordWidth; - } - else - { - spaceLeft -= wordWidthWithSpace; - result += words[j] + " "; - } - } - result += "\n"; - } - return result; -}; - -/** - * Destroys this text object - * - * @method destroy - * @param destroyTexture {Boolean} - */ -PIXI.Text.prototype.destroy = function(destroyTexture) -{ - if(destroyTexture) - { - this.texture.destroy(); - } - -}; - -PIXI.Text.heightCache = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using - * http://www.angelcode.com/products/bmfont/ for windows or - * http://www.bmglyph.com/ for mac. - * - * @class BitmapText - * @extends DisplayObjectContainer - * @constructor - * @param text {String} The copy that you would like the text to display - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText = function(text, style) -{ - PIXI.DisplayObjectContainer.call(this); - - this.setText(text); - this.setStyle(style); - this.updateText(); - this.dirty = false - -}; - -// constructor -PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; - -/** - * Set the copy for the text object - * - * @method setText - * @param text {String} The copy that you would like the text to display - */ -PIXI.BitmapText.prototype.setText = function(text) -{ - this.text = text || " "; - this.dirty = true; -}; - -/** - * Set the style of the text - * - * @method setStyle - * @param style {Object} The style parameters - * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) - * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") - */ -PIXI.BitmapText.prototype.setStyle = function(style) -{ - style = style || {}; - style.align = style.align || "left"; - this.style = style; - - var font = style.font.split(" "); - this.fontName = font[font.length - 1]; - this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; - - this.dirty = true; -}; - -/** - * Renders text - * - * @method updateText - * @private - */ -PIXI.BitmapText.prototype.updateText = function() -{ - var data = PIXI.BitmapText.fonts[this.fontName]; - var pos = new PIXI.Point(); - var prevCharCode = null; - var chars = []; - var maxLineWidth = 0; - var lineWidths = []; - var line = 0; - var scale = this.fontSize / data.size; - for(var i = 0; i < this.text.length; i++) - { - var charCode = this.text.charCodeAt(i); - if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) - { - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - line++; - - pos.x = 0; - pos.y += data.lineHeight; - prevCharCode = null; - continue; - } - - var charData = data.chars[charCode]; - if(!charData) continue; - - if(prevCharCode && charData[prevCharCode]) - { - pos.x += charData.kerning[prevCharCode]; - } - chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); - pos.x += charData.xAdvance; - - prevCharCode = charCode; - } - - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - - var lineAlignOffsets = []; - for(i = 0; i <= line; i++) - { - var alignOffset = 0; - if(this.style.align == "right") - { - alignOffset = maxLineWidth - lineWidths[i]; - } - else if(this.style.align == "center") - { - alignOffset = (maxLineWidth - lineWidths[i]) / 2; - } - lineAlignOffsets.push(alignOffset); - } - - for(i = 0; i < chars.length; i++) - { - var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); - c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; - c.position.y = chars[i].position.y * scale; - c.scale.x = c.scale.y = scale; - this.addChild(c); - } - - this.width = pos.x * scale; - this.height = (pos.y + data.lineHeight) * scale; -}; - -/** - * Updates the transfor of this object - * - * @method updateTransform - * @private - */ -PIXI.BitmapText.prototype.updateTransform = function() -{ - if(this.dirty) - { - while(this.children.length > 0) - { - this.removeChild(this.getChildAt(0)); - } - this.updateText(); - - this.dirty = false; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - -PIXI.BitmapText.fonts = {}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - /** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive - * This manager also supports multitouch. - * - * @class InteractionManager - * @constructor - * @param stage {Stage} The stage to handle interactions - */ -PIXI.InteractionManager = function(stage) -{ - /** - * a refference to the stage - * - * @property stage - * @type Stage - */ - this.stage = stage; - - /** - * the mouse data - * - * @property mouse - * @type InteractionData - */ - this.mouse = new PIXI.InteractionData(); - - /** - * an object that stores current touches (InteractionData) by id reference - * - * @property touchs - * @type Object - */ - this.touchs = {}; - - - - // helpers - this.tempPoint = new PIXI.Point(); - //this.tempMatrix = mat3.create(); - - this.mouseoverEnabled = true; - - //tiny little interactiveData pool! - this.pool = []; - - this.interactiveItems = []; - this.interactionDOMElement = null; - - //this will make it so that you dont have to call bind all the time - this.onMouseMove = this.onMouseMove.bind( this ); - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseOut = this.onMouseOut.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - - this.onTouchStart = this.onTouchStart.bind(this); - this.onTouchEnd = this.onTouchEnd.bind(this); - this.onTouchMove = this.onTouchMove.bind(this); - - - this.last = 0; -} - -// constructor -PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; - -/** - * Collects an interactive sprite recursively to have their interactions managed - * - * @method collectInteractiveSprite - * @param displayObject {DisplayObject} the displayObject to collect - * @param iParent {DisplayObject} - * @private - */ -PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) -{ - var children = displayObject.children; - var length = children.length; - - /// make an interaction tree... {item.__interactiveParent} - for (var i = length-1; i >= 0; i--) - { - var child = children[i]; - -// if(child.visible) { - // push all interactive bits - if(child.interactive) - { - iParent.interactiveChildren = true; - //child.__iParent = iParent; - this.interactiveItems.push(child); - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, child); - } - } - else - { - child.__iParent = null; - - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, iParent); - } - } -// } - } -} - -/** - * Sets the target for event delegation - * - * @method setTarget - * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to - * @private - */ -PIXI.InteractionManager.prototype.setTarget = function(target) -{ - this.target = target; - - //check if the dom element has been set. If it has don't do anything - if( this.interactionDOMElement === null ) { - - this.setTargetDomElement( target.view ); - } - - document.body.addEventListener('mouseup', this.onMouseUp, true); -} - - -/** - * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM - * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element - * to receive those events - * - * @method setTargetDomElement - * @param domElement {DOMElement} the dom element which will receive mouse and touch events - * @private - */ -PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) -{ - //remove previouse listeners - if( this.interactionDOMElement !== null ) - { - this.interactionDOMElement.style['-ms-content-zooming'] = ''; - this.interactionDOMElement.style['-ms-touch-action'] = ''; - - this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - } - - - if (window.navigator.msPointerEnabled) - { - // time to remove some of that zoom in ja.. - domElement.style['-ms-content-zooming'] = 'none'; - domElement.style['-ms-touch-action'] = 'none'; - - // DO some window specific touch! - } - - this.interactionDOMElement = domElement; - - domElement.addEventListener('mousemove', this.onMouseMove, true); - domElement.addEventListener('mousedown', this.onMouseDown, true); - domElement.addEventListener('mouseout', this.onMouseOut, true); - - // aint no multi touch just yet! - domElement.addEventListener('touchstart', this.onTouchStart, true); - domElement.addEventListener('touchend', this.onTouchEnd, true); - domElement.addEventListener('touchmove', this.onTouchMove, true); -} - - -/** - * updates the state of interactive objects - * - * @method update - * @private - */ -PIXI.InteractionManager.prototype.update = function() -{ - if(!this.target)return; - - // frequency of 30fps?? - var now = Date.now(); - var diff = now - this.last; - diff = (diff * 30) / 1000; - if(diff < 1)return; - this.last = now; - // - - // ok.. so mouse events?? - // yes for now :) - // OPTIMSE - how often to check?? - if(this.dirty) - { - this.dirty = false; - - var len = this.interactiveItems.length; - - for (var i=0; i < len; i++) { - this.interactiveItems[i].interactiveChildren = false; - } - - this.interactiveItems = []; - - if(this.stage.interactive)this.interactiveItems.push(this.stage); - // go through and collect all the objects that are interactive.. - this.collectInteractiveSprite(this.stage, this.stage); - } - - // loop through interactive objects! - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - - //if(!item.visible)continue; - - // OPTIMISATION - only calculate every time if the mousemove function exists.. - // OK so.. does the object have any other interactive functions? - // hit-test the clip! - - - if(item.mouseover || item.mouseout || item.buttonMode) - { - // ok so there are some functions so lets hit test it.. - item.__hit = this.hitTest(item, this.mouse); - this.mouse.target = item; - // ok so deal with interactions.. - // loks like there was a hit! - if(item.__hit) - { - if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; - - if(!item.__isOver) - { - - if(item.mouseover)item.mouseover(this.mouse); - item.__isOver = true; - } - } - else - { - if(item.__isOver) - { - // roll out! - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } - } - - // ---> - } -} - -/** - * Is called when the mouse moves accross the renderer element - * - * @method onMouseMove - * @param event {Event} The DOM event of the mouse moving - * @private - */ -PIXI.InteractionManager.prototype.onMouseMove = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.interactionDOMElement.getBoundingClientRect(); - - this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); - this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); - - var length = this.interactiveItems.length; - var global = this.mouse.global; - - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousemove) - { - //call the function! - item.mousemove(this.mouse); - } - } -} - -/** - * Is called when the mouse button is pressed down on the renderer element - * - * @method onMouseDown - * @param event {Event} The DOM event of a mouse button being pressed down - * @private - */ -PIXI.InteractionManager.prototype.onMouseDown = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - // loop through inteaction tree... - // hit test each item! -> - // get interactive items under point?? - //stage.__i - var length = this.interactiveItems.length; - var global = this.mouse.global; - - var index = 0; - var parent = this.stage; - - // while - // hit test - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mousedown || item.click) - { - item.__mouseIsDown = true; - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit) - { - //call the function! - if(item.mousedown)item.mousedown(this.mouse); - item.__isDown = true; - - // just the one! - if(!item.interactiveChildren)break; - } - } - } -} - - -PIXI.InteractionManager.prototype.onMouseOut = function(event) -{ - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.__isOver) - { - this.mouse.target = item; - if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; - } - } -} - -/** - * Is called when the mouse button is released on the renderer element - * - * @method onMouseUp - * @param event {Event} The DOM event of a mouse button being released - * @private - */ -PIXI.InteractionManager.prototype.onMouseUp = function(event) -{ - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var global = this.mouse.global; - - - var length = this.interactiveItems.length; - var up = false; - - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - - if(item.mouseup || item.mouseupoutside || item.click) - { - item.__hit = this.hitTest(item, this.mouse); - - if(item.__hit && !up) - { - //call the function! - if(item.mouseup) - { - item.mouseup(this.mouse); - } - if(item.__isDown) - { - if(item.click)item.click(this.mouse); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.mouseupoutside)item.mouseupoutside(this.mouse); - } - } - - item.__isDown = false; - } - } -} - -/** - * Tests if the current mouse coords hit a sprite - * - * @method hitTest - * @param item {DisplayObject} The displayObject to test for a hit - * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit - * @private - */ -PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) -{ - var global = interactionData.global; - - if(item.vcount !== PIXI.visibleCount)return false; - - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, - a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10), - x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; - - interactionData.target = item; - - //a sprite or display object with a hit area defined - if(item.hitArea && item.hitArea.contains) { - if(item.hitArea.contains(x, y)) { - //if(isSprite) - interactionData.target = item; - - return true; - } - - return false; - } - // a sprite with no hitarea defined - else if(isSprite) - { - var width = item.texture.frame.width, - height = item.texture.frame.height, - x1 = -width * item.anchor.x, - y1; - - if(x > x1 && x < x1 + width) - { - y1 = -height * item.anchor.y; - - if(y > y1 && y < y1 + height) - { - // set the target property if a hit is true! - interactionData.target = item - return true; - } - } - } - - var length = item.children.length; - - for (var i = 0; i < length; i++) - { - var tempItem = item.children[i]; - var hit = this.hitTest(tempItem, interactionData); - if(hit) - { - // hmm.. TODO SET CORRECT TARGET? - interactionData.target = item - return true; - } - } - - return false; -} - -/** - * Is called when a touch is moved accross the renderer element - * - * @method onTouchMove - * @param event {Event} The DOM event of a touch moving accross the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchMove = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - touchData.originalEvent = event || window.event; - - // update the touch position - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - } - - var length = this.interactiveItems.length; - for (var i = 0; i < length; i++) - { - var item = this.interactiveItems[i]; - if(item.touchmove)item.touchmove(touchData); - } -} - -/** - * Is called when a touch is started on the renderer element - * - * @method onTouchStart - * @param event {Event} The DOM event of a touch starting on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchStart = function(event) -{ - var rect = this.interactionDOMElement.getBoundingClientRect(); - - var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - - var touchData = this.pool.pop(); - if(!touchData)touchData = new PIXI.InteractionData(); - - touchData.originalEvent = event || window.event; - - this.touchs[touchEvent.identifier] = touchData; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - - if(item.touchstart || item.tap) - { - item.__hit = this.hitTest(item, touchData); - - if(item.__hit) - { - //call the function! - if(item.touchstart)item.touchstart(touchData); - item.__isDown = true; - item.__touchData = touchData; - - if(!item.interactiveChildren)break; - } - } - } - } -} - -/** - * Is called when a touch is ended on the renderer element - * - * @method onTouchEnd - * @param event {Event} The DOM event of a touch ending on the renderer view - * @private - */ -PIXI.InteractionManager.prototype.onTouchEnd = function(event) -{ - //this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) - { - var touchEvent = changedTouches[i]; - var touchData = this.touchs[touchEvent.identifier]; - var up = false; - touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); - touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - - var length = this.interactiveItems.length; - for (var j = 0; j < length; j++) - { - var item = this.interactiveItems[j]; - var itemTouchData = item.__touchData; // <-- Here! - item.__hit = this.hitTest(item, touchData); - - if(itemTouchData == touchData) - { - // so this one WAS down... - touchData.originalEvent = event || window.event; - // hitTest?? - - if(item.touchend || item.tap) - { - if(item.__hit && !up) - { - if(item.touchend)item.touchend(touchData); - if(item.__isDown) - { - if(item.tap)item.tap(touchData); - } - - if(!item.interactiveChildren)up = true; - } - else - { - if(item.__isDown) - { - if(item.touchendoutside)item.touchendoutside(touchData); - } - } - - item.__isDown = false; - } - - item.__touchData = null; - - } - else - { - - } - } - // remove the touch.. - this.pool.push(touchData); - this.touchs[touchEvent.identifier] = null; - } -} - -/** - * Holds all information related to an Interaction event - * - * @class InteractionData - * @constructor - */ -PIXI.InteractionData = function() -{ - /** - * This point stores the global coords of where the touch/mouse event happened - * - * @property global - * @type Point - */ - this.global = new PIXI.Point(); - - // this is here for legacy... but will remove - this.local = new PIXI.Point(); - - /** - * The target Sprite that was interacted with - * - * @property target - * @type Sprite - */ - this.target; - - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @property originalEvent - * @type Event - */ - this.originalEvent; -} - -/** - * This will return the local coords of the specified displayObject for this InteractionData - * - * @method getLocalPosition - * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off - * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject - */ -PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) -{ - var worldTransform = displayObject.worldTransform; - var global = this.global; - - // do a cheeky transform to get the mouse coords; - var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], - a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10); - // set the mouse coords... - return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, - a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) -} - -// constructor -PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A Stage represents the root of the display tree. Everything connected to the stage is rendered - * - * @class Stage - * @extends DisplayObjectContainer - * @constructor - * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format - * like: 0xFFFFFF for white - */ -PIXI.Stage = function(backgroundColor) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * [read-only] Current transform of the object based on world (parent) factors - * - * @property worldTransform - * @type Mat3 - * @readOnly - * @private - */ - this.worldTransform = PIXI.mat3.create(); - - /** - * Whether or not the stage is interactive - * - * @property interactive - * @type Boolean - */ - this.interactive = true; - - /** - * The interaction manage for this stage, manages all interactive activity on the stage - * - * @property interactive - * @type InteractionManager - */ - this.interactionManager = new PIXI.InteractionManager(this); - - /** - * Whether the stage is dirty and needs to have interactions updated - * - * @property dirty - * @type Boolean - * @private - */ - this.dirty = true; - - this.__childrenAdded = []; - this.__childrenRemoved = []; - - //the stage is it's own stage - this.stage = this; - - //optimize hit detection a bit - this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); - - this.setBackgroundColor(backgroundColor); - this.worldVisible = true; -} - -// constructor -PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Stage.prototype.constructor = PIXI.Stage; - -/** - * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. - * This is useful for when you have other DOM elements ontop of the Canvas element. - * - * @method setInteractionDelegate - * @param domElement {DOMElement} This new domElement which will receive mouse/touch events - */ -PIXI.Stage.prototype.setInteractionDelegate = function(domElement) -{ - this.interactionManager.setTargetDomElement( domElement ); -} - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Stage.prototype.updateTransform = function() -{ - this.worldAlpha = 1; - this.vcount = PIXI.visibleCount; - - for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - -/** - * A polyfill for Function.prototype.bind - * - * @method bind - */ -if (typeof Function.prototype.bind != 'function') { - Function.prototype.bind = (function () { - var slice = Array.prototype.slice; - return function (thisArg) { - var target = this, boundArgs = slice.call(arguments, 1); - - if (typeof target != 'function') throw new TypeError(); - - function bound() { - var args = boundArgs.concat(slice.call(arguments)); - target.apply(this instanceof bound ? this : thisArg, args); - } - - bound.prototype = (function F(proto) { - proto && (F.prototype = proto); - if (!(this instanceof F)) return new F; - })(target.prototype); - - return bound; - }; - })(); -} - -/** - * A wrapper for ajax requests to be handled cross browser - * - * @class AjaxRequest - * @constructor - */ -var AjaxRequest = PIXI.AjaxRequest = function() -{ - var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE - - if (window.ActiveXObject) - { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) - for (var i=0; i>>>>>>>>") - console.log("_") - var safe = 0; - var tmp = item.first; - console.log(tmp); - - while(tmp._iNext) - { - safe++; - tmp = tmp._iNext; - console.log(tmp); - // console.log(tmp); - - if(safe > 100) - { - console.log("BREAK") - break - } - } -} - - - - - - -/** - * https://github.com/mrdoob/eventtarget.js/ - * THankS mr DOob! - */ - -/** - * Adds event emitter functionality to a class - * - * @class EventTarget - * @example - * function MyEmitter() { - * PIXI.EventTarget.call(this); //mixes in event target stuff - * } - * - * var em = new MyEmitter(); - * em.emit({ type: 'eventName', data: 'some data' }); - */ -PIXI.EventTarget = function () { - - var listeners = {}; - - this.addEventListener = this.on = function ( type, listener ) { - - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - } - - }; - - this.dispatchEvent = this.emit = function ( event ) { - - if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { - - return; - - } - - for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { - - listeners[ event.type ][ i ]( event ); - - } - - }; - - this.removeEventListener = this.off = function ( type, listener ) { - - var index = listeners[ type ].indexOf( listener ); - - if ( index !== - 1 ) { - - listeners[ type ].splice( index, 1 ); - - } - - }; - -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @method autoDetectRenderer - * @static - * @param width {Number} the width of the renderers view - * @param height {Number} the height of the renderers view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) - * - * antialias - */ -PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) -{ - if(!width)width = 800; - if(!height)height = 600; - - // BORROWED from Mr Doob (mrdoob.com) - var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); - - if(webgl) - { - var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); - webgl = !ie; - } - - //console.log(webgl); - if( webgl ) - { - return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); - } - - return new PIXI.CanvasRenderer(width, height, view, transparent); -}; - - - -/* - PolyK library - url: http://polyk.ivank.net - Released under MIT licence. - - Copyright (c) 2012 Ivan Kuckir - - 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. - - This is an amazing lib! - - slightly modified by mat groves (matgroves.com); -*/ - -PIXI.PolyK = {}; - -/** - * Triangulates shapes for webGL graphic fills - * - * @method Triangulate - * @namespace PolyK - * @constructor - */ -PIXI.PolyK.Triangulate = function(p) -{ - var sign = true; - - var n = p.length>>1; - if(n<3) return []; - var tgs = []; - var avl = []; - for(var i=0; i 3) - { - var i0 = avl[(i+0)%al]; - var i1 = avl[(i+1)%al]; - var i2 = avl[(i+2)%al]; - - var ax = p[2*i0], ay = p[2*i0+1]; - var bx = p[2*i1], by = p[2*i1+1]; - var cx = p[2*i2], cy = p[2*i2+1]; - - var earFound = false; - if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) - { - earFound = true; - for(var j=0; j 3*al) - { - // need to flip flip reverse it! - // reset! - if(sign) - { - var tgs = []; - avl = []; - for(var i=0; i= 0) && (v >= 0) && (u + v < 1); -} - -/** - * Checks if a shape is convex - * - * @class _convex - * @namespace PolyK - * @private - */ -PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) -{ - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.initDefaultShaders = function() -{ - PIXI.primitiveShader = new PIXI.PrimitiveShader(); - PIXI.primitiveShader.init(); - - PIXI.stripShader = new PIXI.StripShader(); - PIXI.stripShader.init(); - - PIXI.defaultShader = new PIXI.PixiShader(); - PIXI.defaultShader.init(); - - var gl = PIXI.gl; - var shaderProgram = PIXI.defaultShader.program; - - - gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.activatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.primitiveShader.program); - - gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - - gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); -} - -PIXI.deactivatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - - gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); - gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); - - gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); - gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); - gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); - -} - -PIXI.activateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.stripShader.program); - // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -PIXI.deactivateStripShader = function() -{ - var gl = PIXI.gl; - - gl.useProgram(PIXI.defaultShader.program); - //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); -} - -/* - -SHADER COMPILER HELPERS -*/ - -PIXI.CompileVertexShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); -} - -PIXI.CompileFragmentShader = function(gl, shaderSrc) -{ - return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); -} - -PIXI._CompileShader = function(gl, shaderSrc, shaderType) -{ - var src = shaderSrc.join("\n"); - var shader = gl.createShader(shaderType); - gl.shaderSource(shader, src); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - console.log(gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -} - - -PIXI.compileProgram = function(vertexSrc, fragmentSrc) -{ - var gl = PIXI.gl; - var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); - var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); - - var shaderProgram = gl.createProgram(); - - gl.attachShader(shaderProgram, vertexShader); - gl.attachShader(shaderProgram, fragmentShader); - gl.linkProgram(shaderProgram); - - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - console.log("Could not initialise shaders"); - } - - return shaderProgram; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PixiShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision lowp float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", - "}" - ]; - -} - -PIXI.PixiShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - // add those custom shaders! - for (var key in this.uniforms) - { - - // get the uniform locations.. - // program[key] = - this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); - - - } - - this.program = program; -} - -PIXI.PixiShader.prototype.syncUniforms = function() -{ - var gl = PIXI.gl; - - for (var key in this.uniforms) - { - //var - var type = this.uniforms[key].type; - - // need to grow this! - if(type == "f") - { - gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - if(type == "f2") - { - // console.log(this.program[key]) - gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); - } - else if(type == "f4") - { - // console.log(this.uniforms[key].value) - gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if(type == "mat4") - { - gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, false, this.uniforms[key].value); - } - else if(type == "sampler2D") - { - // first texture... - var texture = this.uniforms[key].value; - - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, texture.baseTexture._glTexture); - - gl.uniform1i(this.uniforms[key].uniformLocation, 1); - - // activate texture.. - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); - } - } - -} - -PIXI.PixiShader.defaultVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "varying vec2 vTextureCoord;", - - "varying float vColor;", - - "const vec2 center = vec2(-1.0, 1.0);", - "void main(void) {", - "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" -]; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.StripShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform float alpha;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", - "gl_FragColor = gl_FragColor * alpha;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "varying vec2 vTextureCoord;", - "varying vec2 offsetVector;", - "varying float vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" - ]; -} - -PIXI.StripShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.uSampler = gl.getUniformLocation(program, "uSampler"); - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.PrimitiveShader = function() -{ - // the webGL program.. - this.program; - - this.fragmentSrc = [ - "precision mediump float;", - "varying vec4 vColor;", - "void main(void) {", - "gl_FragColor = vColor;", - "}" - ]; - - this.vertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec4 aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "uniform vec2 offsetVector;", - "uniform float alpha;", - "varying vec4 vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", - "v -= offsetVector.xyx;", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vColor = aColor * alpha;", - "}" - ]; - -} - -PIXI.PrimitiveShader.prototype.init = function() -{ - var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); - - var gl = PIXI.gl; - - gl.useProgram(program); - - // get and store the uniforms for the shader - this.projectionVector = gl.getUniformLocation(program, "projectionVector"); - this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - - // get and store the attributes - this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); - this.colorAttribute = gl.getAttribLocation(program, "aColor"); - - this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); - this.alpha = gl.getUniformLocation(program, "alpha"); - - this.program = program; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A set of functions used by the webGL renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.WebGLGraphics = function() -{ - -} - -/** - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param projection {Object} - */ -PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) -{ - var gl = PIXI.gl; - - if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, - buffer:gl.createBuffer(), - indexBuffer:gl.createBuffer()}; - - if(graphics.dirty) - { - graphics.dirty = false; - - if(graphics.clearDirty) - { - graphics.clearDirty = false; - - graphics._webGL.lastIndex = 0; - graphics._webGL.points = []; - graphics._webGL.indices = []; - - } - - PIXI.WebGLGraphics.updateGraphics(graphics); - } - - PIXI.activatePrimitiveShader(); - - // This could be speeded up fo sure! - var m = PIXI.mat3.clone(graphics.worldTransform); - - PIXI.mat3.transpose(m); - - // set the matrix transform for the - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); - - gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); - gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - - gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - - - gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); - - PIXI.deactivatePrimitiveShader(); - - - // return to default shader... -// PIXI.activateShader(PIXI.defaultShader); -} - -/** - * Updates the graphics object - * - * @static - * @private - * @method updateGraphics - * @param graphics {Graphics} - */ -PIXI.WebGLGraphics.updateGraphics = function(graphics) -{ - for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - - if(data.type == PIXI.Graphics.POLY) - { - if(data.fill) - { - if(data.points.length>3) - PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); - } - - if(data.lineWidth > 0) - { - PIXI.WebGLGraphics.buildLine(data, graphics._webGL); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); - } - else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) - { - PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); - } - }; - - graphics._webGL.lastIndex = graphics.graphicsData.length; - - var gl = PIXI.gl; - - graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); - - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); - - graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); -} - -/** - * Builds a rectangle to draw - * - * @static - * @private - * @method buildRectangle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vertPos = verts.length/6; - - // start - verts.push(x, y); - verts.push(r, g, b, alpha); - - verts.push(x + width, y); - verts.push(r, g, b, alpha); - - verts.push(x , y + height); - verts.push(r, g, b, alpha); - - verts.push(x + width, y + height); - verts.push(r, g, b, alpha); - - // insert 2 dead triangles.. - indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) - } - - if(graphicsData.lineWidth) - { - graphicsData.points = [x, y, - x + width, y, - x + width, y + height, - x, y + height, - x, y]; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a circle to draw - * - * @static - * @private - * @method buildCircle - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) -{ - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - - var totalSegs = 40; - var seg = (Math.PI * 2) / totalSegs ; - - if(graphicsData.fill) - { - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - indices.push(vecPos); - - for (var i=0; i < totalSegs + 1 ; i++) - { - verts.push(x,y, r, g, b, alpha); - - verts.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height, - r, g, b, alpha); - - indices.push(vecPos++, vecPos++); - }; - - indices.push(vecPos-1); - } - - if(graphicsData.lineWidth) - { - graphicsData.points = []; - - for (var i=0; i < totalSegs + 1; i++) - { - graphicsData.points.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height) - }; - - PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); - } - -} - -/** - * Builds a line to draw - * - * @static - * @private - * @method buildLine - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) -{ - // TODO OPTIMISE! - - var wrap = true; - var points = graphicsData.points; - if(points.length == 0)return; - - // if the line width is an odd number add 0.5 to align to a whole pixel - if(graphicsData.lineWidth%2) - { - for (var i = 0; i < points.length; i++) { - points[i] += 0.5; - }; - } - - // get first and last point.. figure out the middle! - var firstPoint = new PIXI.Point( points[0], points[1] ); - var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - // if the first point is the last point - goona have issues :) - if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) - { - points.pop(); - points.pop(); - - lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - - var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; - var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - - points.unshift(midPointX, midPointY); - points.push(midPointX, midPointY) - } - - var verts = webGLData.points; - var indices = webGLData.indices; - var length = points.length / 2; - var indexCount = points.length; - var indexStart = verts.length/6; - - // DRAW the Line - var width = graphicsData.lineWidth / 2; - - // sort color - var color = HEXtoRGB(graphicsData.lineColor); - var alpha = graphicsData.lineAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var p1x, p1y, p2x, p2y, p3x, p3y; - var perpx, perpy, perp2x, perp2y, perp3x, perp3y; - var ipx, ipy; - var a1, b1, c1, a2, b2, c2; - var denom, pdist, dist; - - p1x = points[0]; - p1y = points[1]; - - p2x = points[2]; - p2y = points[3]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - // start - verts.push(p1x - perpx , p1y - perpy, - r, g, b, alpha); - - verts.push(p1x + perpx , p1y + perpy, - r, g, b, alpha); - - for (var i = 1; i < length-1; i++) - { - p1x = points[(i-1)*2]; - p1y = points[(i-1)*2 + 1]; - - p2x = points[(i)*2] - p2y = points[(i)*2 + 1] - - p3x = points[(i+1)*2]; - p3y = points[(i+1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - perp2x = -(p2y - p3y); - perp2y = p2x - p3x; - - dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); - perp2x /= dist; - perp2y /= dist; - perp2x *= width; - perp2y *= width; - - a1 = (-perpy + p1y) - (-perpy + p2y); - b1 = (-perpx + p2x) - (-perpx + p1x); - c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); - a2 = (-perp2y + p3y) - (-perp2y + p2y); - b2 = (-perp2x + p2x) - (-perp2x + p3x); - c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - - denom = a1*b2 - a2*b1; - - if(Math.abs(denom) < 0.1 ) - { - - denom+=10.1; - verts.push(p2x - perpx , p2y - perpy, - r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy, - r, g, b, alpha); - - continue; - } - - px = (b1*c2 - b2*c1)/denom; - py = (a2*c1 - a1*c2)/denom; - - - pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - - - if(pdist > 140 * 140) - { - perp3x = perpx - perp2x; - perp3y = perpy - perp2y; - - dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); - perp3x /= dist; - perp3y /= dist; - perp3x *= width; - perp3y *= width; - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x + perp3x, p2y +perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - indexCount++; - } - else - { - - verts.push(px , py); - verts.push(r, g, b, alpha); - - verts.push(p2x - (px-p2x), p2y - (py - p2y)); - verts.push(r, g, b, alpha); - } - } - - p1x = points[(length-2)*2] - p1y = points[(length-2)*2 + 1] - - p2x = points[(length-1)*2] - p2y = points[(length-1)*2 + 1] - - perpx = -(p1y - p2y) - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - verts.push(p2x - perpx , p2y - perpy) - verts.push(r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy) - verts.push(r, g, b, alpha); - - indices.push(indexStart); - - for (var i=0; i < indexCount; i++) - { - indices.push(indexStart++); - }; - - indices.push(indexStart-1); -} - -/** - * Builds a polygon to draw - * - * @static - * @private - * @method buildPoly - * @param graphics {Graphics} - * @param webGLData {Object} - */ -PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) -{ - var points = graphicsData.points; - if(points.length < 6)return; - - // get first and last point.. figure out the middle! - var verts = webGLData.points; - var indices = webGLData.indices; - - var length = points.length / 2; - - // sort color - var color = HEXtoRGB(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var triangles = PIXI.PolyK.Triangulate(points); - - var vertPos = verts.length / 6; - - for (var i=0; i < triangles.length; i+=3) - { - indices.push(triangles[i] + vertPos); - indices.push(triangles[i] + vertPos); - indices.push(triangles[i+1] + vertPos); - indices.push(triangles[i+2] +vertPos); - indices.push(triangles[i+2] + vertPos); - }; - - for (var i = 0; i < length; i++) - { - verts.push(points[i * 2], points[i * 2 + 1], - r, g, b, alpha); - }; -} - -function HEXtoRGB(hex) { - return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); - -// an instance of the gl context.. -// only one at the moment :/ -PIXI.gl; - -/** - * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer - * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. - * So no need for Sprite Batch's or Sprite Cloud's - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class WebGLRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) - * - */ -PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) -{ - // do a catch.. only 1 webGL renderer.. - - this.transparent = !!transparent; - - this.width = width || 800; - this.height = height || 600; - - this.view = view || document.createElement( 'canvas' ); - this.view.width = this.width; - this.view.height = this.height; - - // deal with losing context.. - var scope = this; - this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) - this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) - - this.batchs = []; - - var options = { - alpha: this.transparent, - antialias:!!antialias, // SPEED UP?? - premultipliedAlpha:false, - stencil:true - } - - //try 'experimental-webgl' - try { - PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); - } catch (e) { - //try 'webgl' - try { - PIXI.gl = this.gl = this.view.getContext("webgl", options); - } catch (e) { - // fail, not able to get a context - throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); - } - } - - PIXI.initDefaultShaders(); - - - - - // PIXI.activateDefaultShader(); - - var gl = this.gl; - - gl.useProgram(PIXI.defaultShader.program); - - - PIXI.WebGLRenderer.gl = gl; - - this.batch = new PIXI.WebGLBatch(gl); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, this.transparent); - - PIXI.projection = new PIXI.Point(400, 300); - PIXI.offset = new PIXI.Point(0, 0); - - // TODO remove thease globals.. - - this.resize(this.width, this.height); - this.contextLost = false; - - //PIXI.pushShader(PIXI.defaultShader); - - this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); - // this.stageRenderGroup. = this.transparent -} - -// constructor -PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; - -/** - * Gets a new WebGLBatch from the pool - * - * @static - * @method getBatch - * @return {WebGLBatch} - * @private - */ -PIXI.WebGLRenderer.getBatch = function() -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * Puts a batch back into the pool - * - * @static - * @method returnBatch - * @param batch {WebGLBatch} The batch to return - * @private - */ -PIXI.WebGLRenderer.returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * Renders the stage to its webGL view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.WebGLRenderer.prototype.render = function(stage) -{ - if(this.contextLost)return; - - - // if rendering a new stage clear the batchs.. - if(this.__stage !== stage) - { - // TODO make this work - // dont think this is needed any more? - this.__stage = stage; - this.stageRenderGroup.setRenderable(stage); - } - - // update any textures - PIXI.WebGLRenderer.updateTextures(); - - // update the scene graph - PIXI.visibleCount++; - stage.updateTransform(); - - var gl = this.gl; - - // -- Does this need to be set every frame? -- // - gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); - gl.clear(gl.COLOR_BUFFER_BIT); - - // HACK TO TEST - - this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - this.stageRenderGroup.render(PIXI.projection); - - // interaction - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // after rendering lets confirm all frames that have been uodated.. - if(PIXI.Texture.frameUpdates.length > 0) - { - for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) - { - PIXI.Texture.frameUpdates[i].updateFrame = false; - }; - - PIXI.Texture.frameUpdates = []; - } -} - -/** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - //TODO break this out into a texture manager... - for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; -} - -/** - * Updates a loaded webgl texture - * - * @static - * @method updateTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.updateTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(!texture._glTexture) - { - texture._glTexture = gl.createTexture(); - } - - if(texture.hasLoaded) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - } -} - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - var gl = PIXI.gl; - - if(texture._glTexture) - { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); - } -} - -/** - * resizes the webGL view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the webGL view - * @param height {Number} the new height of the webGL view - */ -PIXI.WebGLRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; - - this.gl.viewport(0, 0, this.width, this.height); - - //var projectionMatrix = this.projectionMatrix; - - PIXI.projection.x = this.width/2; - PIXI.projection.y = -this.height/2; - - //PIXI.size.x = this.width/2; - //PIXI.size.y = -this.height/2; - -// projectionMatrix[0] = 2/this.width; -// projectionMatrix[5] = -2/this.height; -// projectionMatrix[12] = -1; -// projectionMatrix[13] = 1; -} - -/** - * Handles a lost webgl context - * - * @method handleContextLost - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextLost = function(event) -{ - event.preventDefault(); - this.contextLost = true; -} - -/** - * Handles a restored webgl context - * - * @method handleContextRestored - * @param event {Event} - * @private - */ -PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) -{ - this.gl = this.view.getContext("experimental-webgl", { - alpha: true - }); - - this.initShaders(); - - for(var key in PIXI.TextureCache) - { - var texture = PIXI.TextureCache[key].baseTexture; - texture._glTexture = null; - PIXI.WebGLRenderer.updateTexture(texture); - }; - - for (var i=0; i < this.batchs.length; i++) - { - this.batchs[i].restoreLostContext(this.gl)// - this.batchs[i].dirty = true; - }; - - PIXI._restoreBatchs(this.gl); - - this.contextLost = false; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI._batchs = []; - -/** - * @private - */ -PIXI._getBatch = function(gl) -{ - if(PIXI._batchs.length == 0) - { - return new PIXI.WebGLBatch(gl); - } - else - { - return PIXI._batchs.pop(); - } -} - -/** - * @private - */ -PIXI._returnBatch = function(batch) -{ - batch.clean(); - PIXI._batchs.push(batch); -} - -/** - * @private - */ -PIXI._restoreBatchs = function(gl) -{ - for (var i=0; i < PIXI._batchs.length; i++) - { - PIXI._batchs[i].restoreLostContext(gl); - }; -} - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. - * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites - * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled - * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @constructor - * @param gl {WebGLContext} an instance of the webGL context - */ -PIXI.WebGLBatch = function(gl) -{ - this.gl = gl; - - this.size = 0; - - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - this.blendMode = PIXI.blendModes.NORMAL; - this.dynamicSize = 1; -} - -// constructor -PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; - -/** - * Cleans the batch so that is can be returned to an object pool and reused - * - * @method clean - */ -PIXI.WebGLBatch.prototype.clean = function() -{ - this.verticies = []; - this.uvs = []; - this.indices = []; - this.colors = []; - this.dynamicSize = 1; - this.texture = null; - this.last = null; - this.size = 0; - this.head; - this.tail; -} - -/** - * Recreates the buffers in the event of a context loss - * - * @method restoreLostContext - * @param gl {WebGLContext} - */ -PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) -{ - this.gl = gl; - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); -} - -/** - * inits the batch's texture and blend mode based if the supplied sprite - * - * @method init - * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with - * the same base texture and blend mode will be allowed to be added to this batch - */ -PIXI.WebGLBatch.prototype.init = function(sprite) -{ - sprite.batch = this; - this.dirty = true; - this.blendMode = sprite.blendMode; - this.texture = sprite.texture.baseTexture; - this.head = sprite; - this.tail = sprite; - this.size = 1; - - this.growBatch(); -} - -/** - * inserts a sprite before the specified sprite - * - * @method insertBefore - * @param sprite {Sprite} the sprite to be added - * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite - */ -PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - var tempPrev = nextSprite.__prev; - nextSprite.__prev = sprite; - sprite.__next = nextSprite; - - if(tempPrev) - { - sprite.__prev = tempPrev; - tempPrev.__next = sprite; - } - else - { - this.head = sprite; - } -} - -/** - * inserts a sprite after the specified sprite - * - * @method insertAfter - * @param sprite {Sprite} the sprite to be added - * @param previousSprite {Sprite} the first sprite will be inserted after this sprite - */ -PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) -{ - this.size++; - - sprite.batch = this; - this.dirty = true; - - var tempNext = previousSprite.__next; - previousSprite.__next = sprite; - sprite.__prev = previousSprite; - - if(tempNext) - { - sprite.__next = tempNext; - tempNext.__prev = sprite; - } - else - { - this.tail = sprite - } -} - -/** - * removes a sprite from the batch - * - * @method remove - * @param sprite {Sprite} the sprite to be removed - */ -PIXI.WebGLBatch.prototype.remove = function(sprite) -{ - this.size--; - - if(this.size == 0) - { - sprite.batch = null; - sprite.__prev = null; - sprite.__next = null; - return; - } - - if(sprite.__prev) - { - sprite.__prev.__next = sprite.__next; - } - else - { - this.head = sprite.__next; - this.head.__prev = null; - } - - if(sprite.__next) - { - sprite.__next.__prev = sprite.__prev; - } - else - { - this.tail = sprite.__prev; - this.tail.__next = null - } - - sprite.batch = null; - sprite.__next = null; - sprite.__prev = null; - this.dirty = true; -} - -/** - * Splits the batch into two with the specified sprite being the start of the new batch. - * - * @method split - * @param sprite {Sprite} the sprite that indicates where the batch should be split - * @return {WebGLBatch} the new batch - */ -PIXI.WebGLBatch.prototype.split = function(sprite) -{ - this.dirty = true; - - var batch = new PIXI.WebGLBatch(this.gl); - batch.init(sprite); - batch.texture = this.texture; - batch.tail = this.tail; - - this.tail = sprite.__prev; - this.tail.__next = null; - - sprite.__prev = null; - // return a splite batch! - - // TODO this size is wrong! - // need to recalculate :/ problem with a linked list! - // unless it gets calculated in the "clean"? - - // need to loop through items as there is no way to know the length on a linked list :/ - var tempSize = 0; - while(sprite) - { - tempSize++; - sprite.batch = batch; - sprite = sprite.__next; - } - - batch.size = tempSize; - this.size -= tempSize; - - return batch; -} - -/** - * Merges two batchs together - * - * @method merge - * @param batch {WebGLBatch} the batch that will be merged - */ -PIXI.WebGLBatch.prototype.merge = function(batch) -{ - this.dirty = true; - - this.tail.__next = batch.head; - batch.head.__prev = this.tail; - - this.size += batch.size; - - this.tail = batch.tail; - - var sprite = batch.head; - while(sprite) - { - sprite.batch = this; - sprite = sprite.__next; - } -} - -/** - * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this - * function is used to increase the size of the batch. It also creates a little extra room so - * that the batch does not need to be resized every time a sprite is added - * - * @method growBatch - */ -PIXI.WebGLBatch.prototype.growBatch = function() -{ - var gl = this.gl; - if( this.size == 1) - { - this.dynamicSize = 1; - } - else - { - this.dynamicSize = this.size * 1.5 - } - // grow verts - this.verticies = new Float32Array(this.dynamicSize * 8); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - - this.uvs = new Float32Array( this.dynamicSize * 8 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); - - this.dirtyUVS = true; - - this.colors = new Float32Array( this.dynamicSize * 4 ); - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); - - this.dirtyColors = true; - - this.indices = new Uint16Array(this.dynamicSize * 6); - var length = this.indices.length/6; - - for (var i=0; i < length; i++) - { - var index2 = i * 6; - var index3 = i * 4; - this.indices[index2 + 0] = index3 + 0; - this.indices[index2 + 1] = index3 + 1; - this.indices[index2 + 2] = index3 + 2; - this.indices[index2 + 3] = index3 + 0; - this.indices[index2 + 4] = index3 + 2; - this.indices[index2 + 5] = index3 + 3; - }; - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); -} - -/** - * Refresh's all the data in the batch and sync's it with the webGL buffers - * - * @method refresh - */ -PIXI.WebGLBatch.prototype.refresh = function() -{ - var gl = this.gl; - - if (this.dynamicSize < this.size) - { - this.growBatch(); - } - - var indexRun = 0; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; - var a, b, c, d, tx, ty; - - var displayObject = this.head; - - while(displayObject) - { - index = indexRun * 8; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - this.uvs[index + 0] = frame.x / tw; - this.uvs[index +1] = frame.y / th; - - this.uvs[index +2] = (frame.x + frame.width) / tw; - this.uvs[index +3] = frame.y / th; - - this.uvs[index +4] = (frame.x + frame.width) / tw; - this.uvs[index +5] = (frame.y + frame.height) / th; - - this.uvs[index +6] = frame.x / tw; - this.uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - - colorIndex = indexRun * 4; - this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; - - displayObject = displayObject.__next; - - indexRun ++; - } - - this.dirtyUVS = true; - this.dirtyColors = true; -} - -/** - * Updates all the relevant geometry and uploads the data to the GPU - * - * @method update - */ -PIXI.WebGLBatch.prototype.update = function() -{ - var gl = this.gl; - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 - - var a, b, c, d, tx, ty; - - var indexRun = 0; - - var displayObject = this.head; - var verticies = this.verticies; - var uvs = this.uvs; - var colors = this.colors; - - while(displayObject) - { - if(displayObject.vcount === PIXI.visibleCount) - { - width = displayObject.texture.frame.width; - height = displayObject.texture.frame.height; - - // TODO trim?? - aX = displayObject.anchor.x;// - displayObject.texture.trim.x - aY = displayObject.anchor.y; //- displayObject.texture.trim.y - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - index = indexRun * 8; - - worldTransform = displayObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - verticies[index + 0 ] = a * w1 + c * h1 + tx; - verticies[index + 1 ] = d * h1 + b * w1 + ty; - - verticies[index + 2 ] = a * w0 + c * h1 + tx; - verticies[index + 3 ] = d * h1 + b * w0 + ty; - - verticies[index + 4 ] = a * w0 + c * h0 + tx; - verticies[index + 5 ] = d * h0 + b * w0 + ty; - - verticies[index + 6] = a * w1 + c * h0 + tx; - verticies[index + 7] = d * h0 + b * w1 + ty; - - if(displayObject.updateFrame || displayObject.texture.updateFrame) - { - this.dirtyUVS = true; - - var texture = displayObject.texture; - - var frame = texture.frame; - var tw = texture.baseTexture.width; - var th = texture.baseTexture.height; - - uvs[index + 0] = frame.x / tw; - uvs[index +1] = frame.y / th; - - uvs[index +2] = (frame.x + frame.width) / tw; - uvs[index +3] = frame.y / th; - - uvs[index +4] = (frame.x + frame.width) / tw; - uvs[index +5] = (frame.y + frame.height) / th; - - uvs[index +6] = frame.x / tw; - uvs[index +7] = (frame.y + frame.height) / th; - - displayObject.updateFrame = false; - } - - // TODO this probably could do with some optimisation.... - if(displayObject.cacheAlpha != displayObject.worldAlpha) - { - displayObject.cacheAlpha = displayObject.worldAlpha; - - var colorIndex = indexRun * 4; - colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; - this.dirtyColors = true; - } - } - else - { - index = indexRun * 8; - - verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; - } - - indexRun++; - displayObject = displayObject.__next; - } -} - -/** - * Draws the batch to the frame buffer - * - * @method render - */ -PIXI.WebGLBatch.prototype.render = function(start, end) -{ - start = start || 0; - - if(end == undefined)end = this.size; - - if(this.dirty) - { - this.refresh(); - this.dirty = false; - } - - if (this.size == 0)return; - - this.update(); - var gl = this.gl; - - //TODO optimize this! - - var shaderProgram = PIXI.defaultShader; - - //gl.useProgram(shaderProgram); - - // update the verts.. - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - // ok.. - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) - gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - // update the uvs - //var isDefault = (shaderProgram == PIXI.shaderProgram) - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - if(this.dirtyUVS) - { - this.dirtyUVS = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); - } - - gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); - - // update color! - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - - if(this.dirtyColors) - { - this.dirtyColors = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); - } - - gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - var len = end - start; - - // DRAW THAT this! - gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * A WebGLBatch Enables a group of sprites to be drawn using the same settings. - * if a group of sprites all have the same baseTexture and blendMode then they can be - * grouped into a batch. All the sprites in a batch can then be drawn in one go by the - * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch - * even if the batch only contains one sprite. Batching is handled automatically by the - * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster - * the webGL renderer will run. - * - * @class WebGLBatch - * @contructor - * @param gl {WebGLContext} An instance of the webGL context - */ -PIXI.WebGLRenderGroup = function(gl, transparent) -{ - this.gl = gl; - this.root; - - this.backgroundColor; - this.transparent = transparent == undefined ? true : transparent; - - this.batchs = []; - this.toRemove = []; - console.log(this.transparent) - this.filterManager = new PIXI.WebGLFilterManager(this.transparent); -} - -// constructor -PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; - -/** - * Add a display object to the webgl renderer - * - * @method setRenderable - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) -{ - // has this changed?? - if(this.root)this.removeDisplayObjectAndChildren(this.root); - - displayObject.worldVisible = displayObject.visible; - - // soooooo // - // to check if any batchs exist already?? - - // TODO what if its already has an object? should remove it - this.root = displayObject; - this.addDisplayObjectAndChildren(displayObject); -} - -/** - * Renders the stage to its webgl view - * - * @method render - * @param projection {Object} - */ -PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - - var gl = this.gl; - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - // will render all the elements in the group - var renderable; - - for (var i=0; i < this.batchs.length; i++) - { - - renderable = this.batchs[i]; - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - continue; - } - - // render special - this.renderSpecial(renderable, projection); - } - -} - -/** - * Renders a specific displayObject - * - * @method renderSpecific - * @param displayObject {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) -{ - PIXI.WebGLRenderer.updateTextures(); - var gl = this.gl; - - gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); - - this.filterManager.begin(projection, buffer); - - // to do! - // render part of the scene... - - var startIndex; - var startBatchIndex; - - var endIndex; - var endBatchIndex; - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.first; - while(nextRenderable._iNext) - { - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - nextRenderable = nextRenderable._iNext; - } - var startBatch = nextRenderable.batch; - //console.log(nextRenderable); - - //console.log(renderable) - if(nextRenderable instanceof PIXI.Sprite) - { - startBatch = nextRenderable.batch; - - var head = startBatch.head; - var next = head; - - // ok now we have the batch.. need to find the start index! - if(head == nextRenderable) - { - startIndex = 0; - } - else - { - startIndex = 1; - - while(head.__next != nextRenderable) - { - startIndex++; - head = head.__next; - } - } - } - else - { - startBatch = nextRenderable; - } - - // Get the LAST renderable object - var lastRenderable = displayObject.last; - while(lastRenderable._iPrev) - { - if(lastRenderable.renderable && lastRenderable.__renderGroup)break; - lastRenderable = lastRenderable._iNext; - } - - if(lastRenderable instanceof PIXI.Sprite) - { - endBatch = lastRenderable.batch; - - var head = endBatch.head; - - if(head == lastRenderable) - { - endIndex = 0; - } - else - { - endIndex = 1; - - while(head.__next != lastRenderable) - { - endIndex++; - head = head.__next; - } - } - } - else - { - endBatch = lastRenderable; - } - - //console.log(endBatch); - // TODO - need to fold this up a bit! - - if(startBatch == endBatch) - { - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex, endIndex+1); - } - else - { - this.renderSpecial(startBatch, projection); - } - return; - } - - // now we have first and last! - startBatchIndex = this.batchs.indexOf(startBatch); - endBatchIndex = this.batchs.indexOf(endBatch); - - // DO the first batch - if(startBatch instanceof PIXI.WebGLBatch) - { - startBatch.render(startIndex); - } - else - { - this.renderSpecial(startBatch, projection); - } - - // DO the middle batchs.. - for (var i=startBatchIndex+1; i < endBatchIndex; i++) - { - renderable = this.batchs[i]; - - if(renderable instanceof PIXI.WebGLBatch) - { - this.batchs[i].render(); - } - else - { - this.renderSpecial(renderable, projection); - } - } - - // DO the last batch.. - if(endBatch instanceof PIXI.WebGLBatch) - { - endBatch.render(0, endIndex+1); - } - else - { - this.renderSpecial(endBatch, projection); - } -} - -/** - * Renders a specific renderable - * - * @method renderSpecial - * @param renderable {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) -{ - - var worldVisible = renderable.vcount === PIXI.visibleCount - - - if(renderable instanceof PIXI.TilingSprite) - { - if(worldVisible)this.renderTilingSprite(renderable, projection); - } - else if(renderable instanceof PIXI.Strip) - { - if(worldVisible)this.renderStrip(renderable, projection); - } - else if(renderable instanceof PIXI.CustomRenderable) - { - if(worldVisible) renderable.renderWebGL(this, projection); - } - else if(renderable instanceof PIXI.Graphics) - { - if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); - } - else if(renderable instanceof PIXI.FilterBlock) - { - this.handleFilterBlock(renderable, projection); - } -} - -flip = false; -var maskStack = []; -var maskPosition = 0; - -//var usedMaskStack = []; - -PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) -{ - /* - * for now only masks are supported.. - */ - var gl = PIXI.gl; - - if(filterBlock.open) - { - if(filterBlock.data instanceof Array) - { - this.filterManager.pushFilter(filterBlock); - // ok so.. - - } - else - { - maskPosition++; - - maskStack.push(filterBlock) - - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - - PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - } - else - { - if(filterBlock.data instanceof Array) - { - this.filterManager.popFilter(); - } - else - { - var maskData = maskStack.pop(filterBlock) - - - if(maskData) - { - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,1,1); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - - PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - }; - - gl.disable(gl.STENCIL_TEST); - } - } -} - -/** - * Updates a webgl texture - * - * @method updateTexture - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) -{ - - // TODO definitely can optimse this function.. - - this.removeObject(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = displayObject.first; - while(previousRenderable != this.root) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - this.insertObject(displayObject, previousRenderable, nextRenderable); -} - -/** - * Adds filter blocks - * - * @method addFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) -{ - start.__renderGroup = this; - end.__renderGroup = this; - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - var previousRenderable = start; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - this.insertAfter(start, previousRenderable); - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var previousRenderable2 = end; - while(previousRenderable2 != this.root.first) - { - previousRenderable2 = previousRenderable2._iPrev; - if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; - } - this.insertAfter(end, previousRenderable2); -} - -/** - * Remove filter blocks - * - * @method removeFilterBlocks - * @param start {FilterBlock} - * @param end {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) -{ - this.removeObject(start); - this.removeObject(end); -} - -/** - * Adds a display object and children to the webgl context - * - * @method addDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); - - /* - * LOOK FOR THE PREVIOUS RENDERABLE - * This part looks for the closest previous sprite that can go into a batch - * It keeps going back until it finds a sprite or the stage - */ - - var previousRenderable = displayObject.first; - while(previousRenderable != this.root.first) - { - previousRenderable = previousRenderable._iPrev; - if(previousRenderable.renderable && previousRenderable.__renderGroup)break; - } - - /* - * LOOK FOR THE NEXT SPRITE - * This part looks for the closest next sprite that can go into a batch - * it keeps looking until it finds a sprite or gets to the end of the display - * scene graph - */ - var nextRenderable = displayObject.last; - while(nextRenderable._iNext) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - - // one the display object hits this. we can break the loop - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - do - { - tempObject.__renderGroup = this; - - if(tempObject.renderable) - { - - this.insertObject(tempObject, previousRenderable, nextRenderable); - previousRenderable = tempObject; - } - - tempObject = tempObject._iNext; - } - while(tempObject != testObject) -} - -/** - * Removes a display object and children to the webgl context - * - * @method removeDisplayObjectAndChildren - * @param displayObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) -{ - if(displayObject.__renderGroup != this)return; - -// var displayObject = displayObject.first; - var lastObject = displayObject.last; - do - { - displayObject.__renderGroup = null; - if(displayObject.renderable)this.removeObject(displayObject); - displayObject = displayObject._iNext; - } - while(displayObject) -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertObject - * @param displayObject {DisplayObject} - * @param previousObject {DisplayObject} - * @param nextObject {DisplayObject} - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) -{ - // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED - var previousSprite = previousObject; - var nextSprite = nextObject; - - /* - * so now we have the next renderable and the previous renderable - * - */ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch - var nextBatch - - if(previousSprite instanceof PIXI.Sprite) - { - previousBatch = previousSprite.batch; - if(previousBatch) - { - if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) - { - previousBatch.insertAfter(displayObject, previousSprite); - return; - } - } - } - else - { - // TODO reword! - previousBatch = previousSprite; - } - - if(nextSprite) - { - if(nextSprite instanceof PIXI.Sprite) - { - nextBatch = nextSprite.batch; - - //batch may not exist if item was added to the display list but not to the webGL - if(nextBatch) - { - if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) - { - nextBatch.insertBefore(displayObject, nextSprite); - return; - } - else - { - if(nextBatch == previousBatch) - { - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(nextSprite); - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var batch = PIXI.WebGLRenderer.getBatch(); - - var index = this.batchs.indexOf( previousBatch ); - batch.init(displayObject); - this.batchs.splice(index+1, 0, batch, splitBatch); - - return; - } - } - } - } - else - { - // TODO re-word! - - nextBatch = nextSprite; - } - } - - /* - * looks like it does not belong to any batch! - * but is also not intersecting one.. - * time to create anew one! - */ - - var batch = PIXI.WebGLRenderer.getBatch(); - batch.init(displayObject); - - if(previousBatch) // if this is invalid it means - { - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, batch); - } - else - { - this.batchs.push(batch); - } - - return; - } - else if(displayObject instanceof PIXI.TilingSprite) - { - - // add to a batch!! - this.initTilingSprite(displayObject); - // this.batchs.push(displayObject); - - } - else if(displayObject instanceof PIXI.Strip) - { - // add to a batch!! - this.initStrip(displayObject); - // this.batchs.push(displayObject); - } - else if(displayObject)// instanceof PIXI.Graphics) - { - //displayObject.initWebGL(this); - - // add to a batch!! - //this.initStrip(displayObject); - //this.batchs.push(displayObject); - } - - this.insertAfter(displayObject, previousSprite); - - // insert and SPLIT! - -} - -/** - * Inserts a displayObject into the linked list - * - * @method insertAfter - * @param item {DisplayObject} - * @param displayObject {DisplayObject} The object to insert - * @private - */ -PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) -{ - if(displayObject instanceof PIXI.Sprite) - { - var previousBatch = displayObject.batch; - - if(previousBatch) - { - // so this object is in a batch! - - // is it not? need to split the batch - if(previousBatch.tail == displayObject) - { - // is it tail? insert in to batchs - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item); - } - else - { - // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // - - // THERE IS A SPLIT IN THIS BATCH! // - var splitBatch = previousBatch.split(displayObject.__next); - - // COOL! - // add it back into the array - /* - * OOPS! - * seems the new sprite is in the middle of a batch - * lets split it.. - */ - var index = this.batchs.indexOf( previousBatch ); - this.batchs.splice(index+1, 0, item, splitBatch); - } - } - else - { - this.batchs.push(item); - } - } - else - { - var index = this.batchs.indexOf( displayObject ); - this.batchs.splice(index+1, 0, item); - } -} - -/** - * Removes a displayObject from the linked list - * - * @method removeObject - * @param displayObject {DisplayObject} The object to remove - * @private - */ -PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) -{ - // loop through children.. - // display object // - - // add a child from the render group.. - // remove it and all its children! - //displayObject.cacheVisible = false;//displayObject.visible; - - /* - * removing is a lot quicker.. - * - */ - var batchToRemove; - - if(displayObject instanceof PIXI.Sprite) - { - // should always have a batch! - var batch = displayObject.batch; - if(!batch)return; // this means the display list has been altered befre rendering - - batch.remove(displayObject); - - if(batch.size==0) - { - batchToRemove = batch; - } - } - else - { - batchToRemove = displayObject; - } - - /* - * Looks like there is somthing that needs removing! - */ - if(batchToRemove) - { - var index = this.batchs.indexOf( batchToRemove ); - if(index == -1)return;// this means it was added then removed before rendered - - // ok so.. check to see if you adjacent batchs should be joined. - // TODO may optimise? - if(index == 0 || index == this.batchs.length-1) - { - // wha - eva! just get of the empty batch! - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - - return; - } - - if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) - { - if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) - { - //console.log("MERGE") - this.batchs[index-1].merge(this.batchs[index+1]); - - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); - this.batchs.splice(index, 2); - return; - } - } - - this.batchs.splice(index, 1); - if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - } -} - - -/** - * Initializes a tiling sprite - * - * @method initTilingSprite - * @param sprite {TilingSprite} The tiling sprite to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) -{ - var gl = this.gl; - - // make the texture tilable.. - - sprite.verticies = new Float32Array([0, 0, - sprite.width, 0, - sprite.width, sprite.height, - 0, sprite.height]); - - sprite.uvs = new Float32Array([0, 0, - 1, 0, - 1, 1, - 0, 1]); - - sprite.colors = new Float32Array([1,1,1,1]); - - sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); - - sprite._vertexBuffer = gl.createBuffer(); - sprite._indexBuffer = gl.createBuffer(); - sprite._uvBuffer = gl.createBuffer(); - sprite._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); - -// return ( (x > 0) && ((x & (x - 1)) == 0) ); - - if(sprite.texture.baseTexture._glTexture) - { - gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - sprite.texture.baseTexture._powerOf2 = true; - } - else - { - sprite.texture.baseTexture._powerOf2 = true; - } -} - -/** - * Renders a Strip - * - * @method renderStrip - * @param strip {Strip} The strip to render - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) -{ - var gl = this.gl; - - PIXI.activateStripShader(); - - var shader = PIXI.stripShader; - - var program = shader.program; - - var m = PIXI.mat3.clone(strip.worldTransform); - - PIXI.mat3.transpose(m); - -// console.log(projection) - // set the matrix transform for the - gl.uniformMatrix3fv(shader.translationMatrix, false, m); - gl.uniform2f(shader.projectionVector, projection.x, projection.y); - gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); - - gl.uniform1f(shader.alpha, strip.worldAlpha); - - /* - if(strip.blendMode == PIXI.blendModes.NORMAL) - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - } - else - { - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); - } - */ - - //console.log("!!") - if(!strip.dirty) - { - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - } - else - { - strip.dirty = false; - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - // console.log(strip.texture.baseTexture._glTexture) - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) - gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); - - } - - gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - - PIXI.deactivateStripShader(); - //gl.useProgram(PIXI.currentProgram); -} - -/** - * Renders a TilingSprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tiling sprite to render - * @param projectionMatrix {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) -{ - var gl = this.gl; - - - var shaderProgram = PIXI.shaderProgram; - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - var offsetX = tilePosition.x/sprite.texture.baseTexture.width; - var offsetY = tilePosition.y/sprite.texture.baseTexture.height; - - var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; - var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; - - sprite.uvs[0] = 0 - offsetX; - sprite.uvs[1] = 0 - offsetY; - - sprite.uvs[2] = (1 * scaleX) -offsetX; - sprite.uvs[3] = 0 - offsetY; - - sprite.uvs[4] = (1 *scaleX) - offsetX; - sprite.uvs[5] = (1 *scaleY) - offsetY; - - sprite.uvs[6] = 0 - offsetX; - sprite.uvs[7] = (1 *scaleY) - offsetY; - - gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) - - this.renderStrip(sprite, projectionMatrix); -} - -/** - * Initializes a strip to be rendered - * - * @method initStrip - * @param strip {Strip} The strip to initialize - * @private - */ -PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) -{ - // build the strip! - var gl = this.gl; - var shaderProgram = this.shaderProgram; - - strip._vertexBuffer = gl.createBuffer(); - strip._indexBuffer = gl.createBuffer(); - strip._uvBuffer = gl.createBuffer(); - strip._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); - - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -PIXI.WebGLFilterManager = function(transparent) -{ - this.transparent = transparent; - - this.filterStack = []; - this.texturePool = []; - - this.offsetX = 0; - this.offsetY = 0; - - this.initShaderBuffers(); -} - -// API - -PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) -{ - this.width = projection.x * 2; - this.height = -projection.y * 2; - this.buffer = buffer; -} - -PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) -{ - var gl = PIXI.gl; - - // filter program - // OPTIMISATION - the first filter is free if its a simple color change? - this.filterStack.push(filterBlock); - - var filter = filterBlock.filterPasses[0]; - - - - this.offsetX += filterBlock.target.filterArea.x; - this.offsetY += filterBlock.target.filterArea.y; - - - - - - var texture = this.texturePool.pop(); - if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); - - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - this.getBounds(filterBlock.target); - - // addpadding? - //displayObject.filterArea.x - - var filterArea = filterBlock.target.filterArea; - - var padidng = filter.padding; - filterArea.x -= padidng; - filterArea.y -= padidng; - filterArea.width += padidng * 2; - filterArea.height += padidng * 2; - - // cap filter to screen size.. - if(filterArea.x < 0)filterArea.x = 0; - if(filterArea.width > this.width)filterArea.width = this.width; - if(filterArea.y < 0)filterArea.y = 0; - if(filterArea.height > this.height)filterArea.height = this.height; - - - //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); - - // console.log(filterArea) - // set view port - gl.viewport(0, 0, filterArea.width, filterArea.height); - - PIXI.projection.x = filterArea.width/2; - PIXI.projection.y = -filterArea.height/2; - - PIXI.offset.x = -filterArea.x; - PIXI.offset.y = -filterArea.y; - - //console.log(PIXI.defaultShader.projectionVector) - // update projection - gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); - //PIXI.primitiveProgram - - gl.colorMask(true, true, true, true); - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - //filter.texture = texture; - filterBlock._glFilterTexture = texture; - - //console.log("PUSH") -} - - -PIXI.WebGLFilterManager.prototype.popFilter = function() -{ - - var gl = PIXI.gl; - - var filterBlock = this.filterStack.pop(); - - - - var filterArea = filterBlock.target.filterArea; - - var texture = filterBlock._glFilterTexture; - - if(filterBlock.filterPasses.length > 1) - { - gl.viewport(0, 0, filterArea.width, filterArea.height); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = 0; - this.vertexArray[1] = filterArea.height; - - this.vertexArray[2] = filterArea.width; - this.vertexArray[3] = filterArea.height; - - this.vertexArray[4] = 0; - this.vertexArray[5] = 0; - - this.vertexArray[6] = filterArea.width; - this.vertexArray[7] = 0; - - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - // nnow set the uvs.. - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - var inputTexture = texture; - var outputTexture = this.texturePool.pop(); - if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); - - // need to clear this FBO as it may have some left over elements from a prvious filter. - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.disable(gl.BLEND); - - for (var i = 0; i < filterBlock.filterPasses.length-1; i++) - { - var filterPass = filterBlock.filterPasses[i]; - - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); - - // draw texture.. - //filterPass.applyFilterPass(filterArea.width, filterArea.height); - this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); - - // swap the textures.. - var temp = inputTexture; - inputTexture = outputTexture; - outputTexture = temp; - - }; - - gl.enable(gl.BLEND); - - texture = inputTexture; - this.texturePool.push(outputTexture); - } - - var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; - - this.offsetX -= filterArea.x; - this.offsetY -= filterArea.y; - - - var sizeX = this.width; - var sizeY = this.height; - - var offsetX = 0; - var offsetY = 0; - - var buffer = this.buffer; - - // time to render the filters texture to the previous scene - if(this.filterStack.length === 0) - { - gl.colorMask(true, true, true, this.transparent); - } - else - { - var currentFilter = this.filterStack[this.filterStack.length-1]; - var filterArea = currentFilter.target.filterArea; - - sizeX = filterArea.width; - sizeY = filterArea.height; - - offsetX = filterArea.x; - offsetY = filterArea.y; - - buffer = currentFilter._glFilterTexture.frameBuffer; - } - - - - // TODO need toremove thease global elements.. - PIXI.projection.x = sizeX/2; - PIXI.projection.y = -sizeY/2; - - PIXI.offset.x = offsetX; - PIXI.offset.y = offsetY; - - - var filterArea = filterBlock.target.filterArea; - var x = filterArea.x-offsetX; - var y = filterArea.y-offsetY; - - // update the buffers.. - // make sure to flip the y! - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = x; - this.vertexArray[1] = y + filterArea.height; - - this.vertexArray[2] = x + filterArea.width; - this.vertexArray[3] = y + filterArea.height; - - this.vertexArray[4] = x; - this.vertexArray[5] = y; - - this.vertexArray[6] = x + filterArea.width; - this.vertexArray[7] = y; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - gl.viewport(0, 0, sizeX, sizeY); - // bind the buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - // apply! - //filter.applyFilterPass(sizeX, sizeY); - this.applyFilterPass(filter, filterArea, sizeX, sizeY); - - // now restore the regular shader.. - gl.useProgram(PIXI.defaultShader.program); - gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); - gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); - - // return the texture to the pool - this.texturePool.push(texture); - filterBlock._glFilterTexture = null; -} - -PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) -{ - // use program - var gl = PIXI.gl; - - if(!filter.shader) - { - var shader = new PIXI.PixiShader(); - - shader.fragmentSrc = filter.fragmentSrc; - shader.uniforms = filter.uniforms; - shader.init(); - - filter.shader = shader; - } - - var shader = filter.shader; - - // set the shader - gl.useProgram(shader.program); - - gl.uniform2f(shader.projectionVector, width/2, -height/2); - gl.uniform2f(shader.offsetVector, 0,0) - - if(filter.uniforms.dimensions) - { - //console.log(filter.uniforms.dimensions) - filter.uniforms.dimensions.value[0] = this.width;//width; - filter.uniforms.dimensions.value[1] = this.height;//height; - filter.uniforms.dimensions.value[2] = this.vertexArray[0]; - filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; - // console.log(this.vertexArray[5]) - } - - shader.syncUniforms(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // draw the filter... - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); -} - -PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() -{ - var gl = PIXI.gl; - - // create some buffers - this.vertexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // bind and upload the vertexs.. - // keep a refferance to the vertexFloatData.. - this.vertexArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.vertexArray, - gl.STATIC_DRAW); - - - // bind and upload the uv buffer - this.uvArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - this.uvArray, - gl.STATIC_DRAW); - - // bind and upload the index - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData( - gl.ELEMENT_ARRAY_BUFFER, - new Uint16Array([0, 1, 2, 1, 3, 2]), - gl.STATIC_DRAW); -} - -PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) -{ - // time to get the width and height of the object! - var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; - var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; - - var tempObject = displayObject.first; - var testObject = displayObject.last._iNext; - - var maxX = -Infinity; - var maxY = -Infinity; - - var minX = Infinity; - var minY = Infinity; - - do - { - // TODO can be optimized! - what if there is no scale / rotation? - - if(tempObject.visible) - { - if(tempObject instanceof PIXI.Sprite) - { - width = tempObject.texture.frame.width; - height = tempObject.texture.frame.height; - - // TODO trim?? - aX = tempObject.anchor.x; - aY = tempObject.anchor.y; - w0 = width * (1-aX); - w1 = width * -aX; - - h0 = height * (1-aY); - h1 = height * -aY; - - doTest = true; - } - else if(tempObject instanceof PIXI.Graphics) - { - tempObject.updateFilterBounds(); - - var bounds = tempObject.bounds; - - width = bounds.width; - height = bounds.height; - - w0 = bounds.x - w1 = bounds.x + bounds.width; - - h0 = bounds.y - h1 = bounds.y + bounds.height; - - doTest = true; - } - } - - if(doTest) - { - worldTransform = tempObject.worldTransform; - - a = worldTransform[0]; - b = worldTransform[3]; - c = worldTransform[1]; - d = worldTransform[4]; - tx = worldTransform[2]; - ty = worldTransform[5]; - - x1 = a * w1 + c * h1 + tx; - y1 = d * h1 + b * w1 + ty; - - x2 = a * w0 + c * h1 + tx; - y2 = d * h1 + b * w0 + ty; - - x3 = a * w0 + c * h0 + tx; - y3 = d * h0 + b * w0 + ty; - - x4 = a * w1 + c * h0 + tx; - y4 = d * h0 + b * w1 + ty; - - minX = x1 < minX ? x1 : minX; - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y1 < minY ? y1 : minY; - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x1 > maxX ? x1 : maxX; - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1 > maxY ? y1 : maxY; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - } - - doTest = false; - tempObject = tempObject._iNext; - - } - while(tempObject != testObject) - - // maximum bounds is the size of the screen.. - //minX = minX > 0 ? minX : 0; - //minY = minY > 0 ? minY : 0; - - displayObject.filterArea.x = minX; - displayObject.filterArea.y = minY; - -// console.log(maxX+ " : " + minX) - displayObject.filterArea.width = maxX - minX; - displayObject.filterArea.height = maxY - minY; -} - -PIXI.FilterTexture = function(width, height) -{ - var gl = PIXI.gl; - - // next time to create a frame buffer and texture - this.frameBuffer = gl.createFramebuffer(); - this.texture = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - this.resize(width, height); -} - -PIXI.FilterTexture.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - var gl = PIXI.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - -} -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. - * Dont forget to add the view to your DOM or you will not see anything :) - * - * @class CanvasRenderer - * @constructor - * @param width=0 {Number} the width of the canvas view - * @param height=0 {Number} the height of the canvas view - * @param view {Canvas} the canvas to use as a view, optional - * @param transparent=false {Boolean} the transparency of the render view, default false - */ -PIXI.CanvasRenderer = function(width, height, view, transparent) -{ - this.transparent = transparent; - - /** - * The width of the canvas view - * - * @property width - * @type Number - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @property height - * @type Number - * @default 600 - */ - this.height = height || 600; - - /** - * The canvas element that the everything is drawn to - * - * @property view - * @type Canvas - */ - this.view = view || document.createElement( 'canvas' ); - - /** - * The canvas context that the everything is drawn to - * @property context - * @type Canvas 2d Context - */ - this.context = this.view.getContext("2d"); - - this.refresh = true; - // hack to enable some hardware acceleration! - //this.view.style["transform"] = "translatez(0)"; - - this.view.width = this.width; - this.view.height = this.height; - this.count = 0; -} - -// constructor -PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; - -/** - * Renders the stage to its canvas view - * - * @method render - * @param stage {Stage} the Stage element to be rendered - */ -PIXI.CanvasRenderer.prototype.render = function(stage) -{ - - //stage.__childrenAdded = []; - //stage.__childrenRemoved = []; - - // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - - PIXI.visibleCount++; - stage.updateTransform(); - - // update the background color - if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; - - this.context.setTransform(1,0,0,1,0,0); - this.context.clearRect(0, 0, this.width, this.height) - this.renderDisplayObject(stage); - //as - - // run interaction! - if(stage.interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget(this); - } - } - - // remove frame updates.. - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates = []; - } - - -} - -/** - * resizes the canvas view to the specified width and height - * - * @method resize - * @param width {Number} the new width of the canvas view - * @param height {Number} the new height of the canvas view - */ -PIXI.CanvasRenderer.prototype.resize = function(width, height) -{ - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; -} - -/** - * Renders a display object - * - * @method renderDisplayObject - * @param displayObject {DisplayObject} The displayObject to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) -{ - // no loger recurrsive! - var transform; - var context = this.context; - - context.globalCompositeOperation = 'source-over'; - - // one the display object hits this. we can break the loop - var testObject = displayObject.last._iNext; - displayObject = displayObject.first; - - do - { - transform = displayObject.worldTransform; - - if(!displayObject.visible) - { - displayObject = displayObject.last._iNext; - continue; - } - - if(!displayObject.renderable) - { - displayObject = displayObject._iNext; - continue; - } - - if(displayObject instanceof PIXI.Sprite) - { - - var frame = displayObject.texture.frame; - - if(frame && frame.width && frame.height) - { - context.globalAlpha = displayObject.worldAlpha; - - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - - context.drawImage(displayObject.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - (displayObject.anchor.x) * -frame.width, - (displayObject.anchor.y) * -frame.height, - frame.width, - frame.height); - } - } - else if(displayObject instanceof PIXI.Strip) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderStrip(displayObject); - } - else if(displayObject instanceof PIXI.TilingSprite) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - this.renderTilingSprite(displayObject); - } - else if(displayObject instanceof PIXI.CustomRenderable) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - displayObject.renderCanvas(this); - } - else if(displayObject instanceof PIXI.Graphics) - { - context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) - PIXI.CanvasGraphics.renderGraphics(displayObject, context); - } - else if(displayObject instanceof PIXI.FilterBlock) - { - if(displayObject.data instanceof PIXI.Graphics) - { - var mask = displayObject.data; - - if(displayObject.open) - { - context.save(); - - var cacheAlpha = mask.alpha; - var maskTransform = mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(mask, context); - context.clip(); - - mask.worldAlpha = cacheAlpha; - } - else - { - context.restore(); - } - } - else - { - // only masks supported right now! - } - } - // count++ - displayObject = displayObject._iNext; - - - } - while(displayObject != testObject) - - -} - -/** - * Renders a flat strip - * - * @method renderStripFlat - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) -{ - var context = this.context; - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - - context.beginPath(); - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - }; - - context.fillStyle = "#FF0000"; - context.fill(); - context.closePath(); -} - -/** - * Renders a tiling sprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tilingsprite to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) -{ - var context = this.context; - - context.globalAlpha = sprite.worldAlpha; - - if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); - - context.beginPath(); - - var tilePosition = sprite.tilePosition; - var tileScale = sprite.tileScale; - - // offset - context.scale(tileScale.x,tileScale.y); - context.translate(tilePosition.x, tilePosition.y); - - context.fillStyle = sprite.__tilePattern; - context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); - - context.scale(1/tileScale.x, 1/tileScale.y); - context.translate(-tilePosition.x, -tilePosition.y); - - context.closePath(); -} - -/** - * Renders a strip - * - * @method renderStrip - * @param strip {Strip} The Strip to render - * @private - */ -PIXI.CanvasRenderer.prototype.renderStrip = function(strip) -{ - var context = this.context; - - // draw triangles!! - var verticies = strip.verticies; - var uvs = strip.uvs; - - var length = verticies.length/2; - this.count++; - for (var i=1; i < length-2; i++) - { - - // draw some triangles! - var index = i*2; - - var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; - var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - - var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; - var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; - - - context.save(); - context.beginPath(); - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - context.closePath(); - - context.clip(); - - - // Compute matrix transform - var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; - var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; - var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; - var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; - var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; - var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; - var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; - - - - - context.transform(delta_a/delta, delta_d/delta, - delta_b/delta, delta_e/delta, - delta_c/delta, delta_f/delta); - - context.drawImage(strip.texture.baseTexture.source, 0, 0); - context.restore(); - }; - -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * A set of functions used by the canvas renderer to draw the primitive graphics data - * - * @class CanvasGraphics - */ -PIXI.CanvasGraphics = function() -{ - -} - - -/* - * Renders the graphics object - * - * @static - * @private - * @method renderGraphics - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphics = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); - - context.lineWidth = data.lineWidth; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.RECT) - { - - if(data.fillColor || data.fillColor === 0) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); - - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); - } - - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - context.closePath(); - - if(data.fill) - { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if(data.lineWidth) - { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.stroke(); - } - } - - }; -} - -/* - * Renders a graphics mask - * - * @static - * @private - * @method renderGraphicsMask - * @param graphics {Graphics} - * @param context {Context2D} - */ -PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) -{ - var worldAlpha = graphics.worldAlpha; - - var len = graphics.graphicsData.length; - if(len === 0)return; - - if(len > 1) - { - len = 1; - console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") - } - - for (var i=0; i < 1; i++) - { - var data = graphics.graphicsData[i]; - var points = data.points; - - if(data.type == PIXI.Graphics.POLY) - { - context.beginPath(); - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) - { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) - { - context.closePath(); - } - - } - else if(data.type == PIXI.Graphics.RECT) - { - context.beginPath(); - context.rect(points[0], points[1], points[2], points[3]); - context.closePath(); - } - else if(data.type == PIXI.Graphics.CIRC) - { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); - context.closePath(); - } - else if(data.type == PIXI.Graphics.ELIP) - { - - // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var elipseData = data.points; - - var w = elipseData[2] * 2; - var h = elipseData[3] * 2; - - var x = elipseData[0] - w/2; - var y = elipseData[1] - h/2; - - context.beginPath(); - - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - } - - - }; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. - * It is important to know that with the webGL renderer only simple polys can be filled at this stage - * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png - * - * @class Graphics - * @extends DisplayObjectContainer - * @constructor - */ -PIXI.Graphics = function() -{ - PIXI.DisplayObjectContainer.call( this ); - - this.renderable = true; - - /** - * The alpha of the fill of this graphics object - * - * @property fillAlpha - * @type Number - */ - this.fillAlpha = 1; - - /** - * The width of any lines drawn - * - * @property lineWidth - * @type Number - */ - this.lineWidth = 0; - - /** - * The color of any lines drawn - * - * @property lineColor - * @type String - */ - this.lineColor = "black"; - - /** - * Graphics data - * - * @property graphicsData - * @type Array - * @private - */ - this.graphicsData = []; - - /** - * Current path - * - * @property currentPath - * @type Object - * @private - */ - this.currentPath = {points:[]}; -} - -// constructor -PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Graphics.prototype.constructor = PIXI.Graphics; - -/** - * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. - * - * @method lineStyle - * @param lineWidth {Number} width of the line to draw, will update the object's stored style - * @param color {Number} color of the line to draw, will update the object's stored style - * @param alpha {Number} alpha of the line to draw, will update the object's stored style - */ -PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.lineWidth = lineWidth || 0; - this.lineColor = color || 0; - this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); -} - -/** - * Moves the current drawing position to (x, y). - * - * @method moveTo - * @param x {Number} the X coord to move to - * @param y {Number} the Y coord to move to - */ -PIXI.Graphics.prototype.moveTo = function(x, y) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.currentPath.points.push(x, y); - - this.graphicsData.push(this.currentPath); -} - -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coord to draw to - * @param y {Number} the Y coord to draw to - */ -PIXI.Graphics.prototype.lineTo = function(x, y) -{ - this.currentPath.points.push(x, y); - this.dirty = true; -} - -/** - * Specifies a simple one-color fill that subsequent calls to other Graphics methods - * (such as lineTo() or drawCircle()) use when drawing. - * - * @method beginFill - * @param color {uint} the color of the fill - * @param alpha {Number} the alpha - */ -PIXI.Graphics.prototype.beginFill = function(color, alpha) -{ - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha == undefined) ? 1 : alpha; -} - -/** - * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. - * - * @method endFill - */ -PIXI.Graphics.prototype.endFill = function() -{ - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; -} - -/** - * @method drawRect - * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle - */ -PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws a circle. - * - * @method drawCircle - * @param x {Number} The X coord of the center of the circle - * @param y {Number} The Y coord of the center of the circle - * @param radius {Number} The radius of the circle - */ -PIXI.Graphics.prototype.drawCircle = function( x, y, radius) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Draws an elipse. - * - * @method drawElipse - * @param x {Number} - * @param y {Number} - * @param width {Number} - * @param height {Number} - */ -PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) -{ - if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; -} - -/** - * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. - * - * @method clear - */ -PIXI.Graphics.prototype.clear = function() -{ - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; - - this.bounds = null//new PIXI.Rectangle(); -} - - -PIXI.Graphics.prototype.updateFilterBounds = function() -{ - if(!this.bounds) - { - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - var points, x, y; - - for (var i = 0; i < this.graphicsData.length; i++) { - - - var data = this.graphicsData[i]; - var type = data.type; - var lineWidth = data.lineWidth; - - points = data.points; - - if(type === PIXI.Graphics.RECT) - { - x = points.x - lineWidth/2; - y = points.y - lineWidth/2; - var width = points.width + lineWidth; - var height = points.height + lineWidth; - - minX = x < minX ? x : minX; - maxX = x + width > maxX ? x + width : maxX; - - minY = y < minY ? x : minY; - maxY = y + height > maxY ? y + height : maxY; - } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) - { - x = points.x; - y = points.y; - var radius = points.radius + lineWidth/2; - - minX = x - radius < minX ? x - radius : minX; - maxX = x + radius > maxX ? x + radius : maxX; - - minY = y - radius < minY ? y - radius : minY; - maxY = y + radius > maxY ? y + radius : maxY; - } - else - { - // POLY - for (var j = 0; j < points.length; j+=2) - { - - x = points[j]; - y = points[j+1]; - - minX = x-lineWidth < minX ? x-lineWidth : minX; - maxX = x+lineWidth > maxX ? x+lineWidth : maxX; - - minY = y-lineWidth < minY ? y-lineWidth : minY; - maxY = y+lineWidth > maxY ? y+lineWidth : maxY; - }; - } - - }; - - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); - - } - -// console.log(this.bounds); -} - -// SOME TYPES: -PIXI.Graphics.POLY = 0; -PIXI.Graphics.RECT = 1; -PIXI.Graphics.CIRC = 2; -PIXI.Graphics.ELIP = 3; - -/** - * @author Mat Groves http://matgroves.com/ - */ - -PIXI.Strip = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - this.texture = texture; - this.blendMode = PIXI.blendModes.NORMAL; - - try - { - this.uvs = new Float32Array([0, 1, - 1, 1, - 1, 0, 0,1]); - - this.verticies = new Float32Array([0, 0, - 0,0, - 0,0, 0, - 0, 0]); - - this.colors = new Float32Array([1, 1, 1, 1]); - - this.indices = new Uint16Array([0, 1, 2, 3]); - } - catch(error) - { - this.uvs = [0, 1, - 1, 1, - 1, 0, 0,1]; - - this.verticies = [0, 0, - 0,0, - 0,0, 0, - 0, 0]; - - this.colors = [1, 1, 1, 1]; - - this.indices = [0, 1, 2, 3]; - } - - - /* - this.uvs = new Float32Array() - this.verticies = new Float32Array() - this.colors = new Float32Array() - this.indices = new Uint16Array() -*/ - this.width = width; - this.height = height; - - // load the texture! - if(texture.baseTexture.hasLoaded) - { - this.width = this.texture.frame.width; - this.height = this.texture.frame.height; - this.updateFrame = true; - } - else - { - this.onTextureUpdateBind = this.onTextureUpdate.bind(this); - this.texture.addEventListener( 'update', this.onTextureUpdateBind ); - } - - this.renderable = true; -} - -// constructor -PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Strip.prototype.constructor = PIXI.Strip; - -PIXI.Strip.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.width = texture.frame.width; - this.height = texture.frame.height; - this.updateFrame = true; -} - -PIXI.Strip.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} -// some helper functions.. - - -/** - * @author Mat Groves http://matgroves.com/ - */ - - -PIXI.Rope = function(texture, points) -{ - PIXI.Strip.call( this, texture ); - this.points = points; - - try - { - this.verticies = 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); - } - catch(error) - { - this.verticies = verticies - - this.uvs = uvs - this.colors = colors - this.indices = indices - } - - this.refresh(); -} - - -// constructor -PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); -PIXI.Rope.prototype.constructor = PIXI.Rope; - -PIXI.Rope.prototype.refresh = function() -{ - var points = this.points; - if(points.length < 1)return; - - var uvs = this.uvs - var indices = this.indices; - var colors = this.colors; - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - - uvs[0] = 0 - uvs[1] = 1 - uvs[2] = 0 - uvs[3] = 1 - - colors[0] = 1; - colors[1] = 1; - - indices[0] = 0; - indices[1] = 1; - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - // time to do some smart drawing! - var amount = i/(total-1) - - if(i%2) - { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount - uvs[index+3] = 1 - - } - else - { - uvs[index] = amount - uvs[index+1] = 0 - - uvs[index+2] = amount - uvs[index+3] = 1 - } - - index = i * 2; - colors[index] = 1; - colors[index+1] = 1; - - index = i * 2; - indices[index] = index; - indices[index + 1] = index + 1; - - lastPoint = point; - } -} - -PIXI.Rope.prototype.updateTransform = function() -{ - - var points = this.points; - if(points.length < 1)return; - - var verticies = this.verticies - - var lastPoint = points[0]; - var nextPoint; - var perp = {x:0, y:0}; - var point = points[0]; - - this.count-=0.2; - - verticies[0] = point.x + perp.x - verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x - verticies[3] = point.y - perp.y//+200 - // time to do some smart drawing! - - var total = points.length; - - for (var i = 1; i < total; i++) - { - - var point = points[i]; - var index = i * 4; - - if(i < points.length-1) - { - nextPoint = points[i+1]; - } - else - { - nextPoint = point - } - - perp.y = -(nextPoint.x - lastPoint.x); - perp.x = nextPoint.y - lastPoint.y; - - var ratio = (1 - (i / (total-1))) * 10; - if(ratio > 1)ratio = 1; - - var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); - var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; - perp.x /= perpLength; - perp.y /= perpLength; - - perp.x *= num; - perp.y *= num; - - verticies[index] = point.x + perp.x - verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x - verticies[index+3] = point.y - perp.y - - lastPoint = point; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); -} - -PIXI.Rope.prototype.setTexture = function(texture) -{ - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - - - - - -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * A tiling sprite is a fast way of rendering a tiling image - * - * @class TilingSprite - * @extends DisplayObjectContainer - * @constructor - * @param texture {Texture} the texture of the tiling sprite - * @param width {Number} the width of the tiling sprite - * @param height {Number} the height of the tiling sprite - */ -PIXI.TilingSprite = function(texture, width, height) -{ - PIXI.DisplayObjectContainer.call( this ); - - /** - * The texture that the sprite is using - * - * @property texture - * @type Texture - */ - this.texture = texture; - - /** - * The width of the tiling sprite - * - * @property width - * @type Number - */ - this.width = width; - - /** - * The height of the tiling sprite - * - * @property height - * @type Number - */ - this.height = height; - - /** - * The scaling of the image that is being tiled - * - * @property tileScale - * @type Point - */ - this.tileScale = new PIXI.Point(1,1); - - /** - * The offset position of the image that is being tiled - * - * @property tilePosition - * @type Point - */ - this.tilePosition = new PIXI.Point(0,0); - - this.renderable = true; - - this.blendMode = PIXI.blendModes.NORMAL -} - -// constructor -PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; - -/** - * Sets the texture of the tiling sprite - * - * @method setTexture - * @param texture {Texture} The PIXI texture that is displayed by the sprite - */ -PIXI.TilingSprite.prototype.setTexture = function(texture) -{ - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.updateFrame = true; -} - -/** - * When the texture is updated, this event will fire to update the frame - * - * @method onTextureUpdate - * @param event - * @private - */ -PIXI.TilingSprite.prototype.onTextureUpdate = function(event) -{ - this.updateFrame = true; -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * - * Awesome JS run time provided by EsotericSoftware - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -/** - * A class that enables the you to import and run your spine animations in pixi. - * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * - * @class Spine - * @extends DisplayObjectContainer - * @constructor - * @param url {String} The url of the spine anim file to be used - */ -PIXI.Spine = function (url) { - PIXI.DisplayObjectContainer.call(this); - - this.spineData = PIXI.AnimCache[url]; - - if (!this.spineData) { - throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - } - - this.skeleton = new spine.Skeleton(this.spineData); - this.skeleton.updateWorldTransform(); - - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); - - this.slotContainers = []; - - for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { - var slot = this.skeleton.drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = new PIXI.DisplayObjectContainer(); - this.slotContainers.push(slotContainer); - this.addChild(slotContainer); - if (!(attachment instanceof spine.RegionAttachment)) { - continue; - } - var spriteName = attachment.rendererObject.name; - var sprite = this.createSprite(slot, attachment.rendererObject); - slot.currentSprite = sprite; - slot.currentSpriteName = spriteName; - slotContainer.addChild(sprite); - } -}; - -PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -PIXI.Spine.prototype.constructor = PIXI.Spine; - -/* - * Updates the object transform for rendering - * - * @method updateTransform - * @private - */ -PIXI.Spine.prototype.updateTransform = function () { - this.lastTime = this.lastTime || Date.now(); - var timeDelta = (Date.now() - this.lastTime) * 0.001; - this.lastTime = Date.now(); - this.state.update(timeDelta); - this.state.apply(this.skeleton); - this.skeleton.updateWorldTransform(); - - var drawOrder = this.skeleton.drawOrder; - for (var i = 0, n = drawOrder.length; i < n; i++) { - var slot = drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = this.slotContainers[i]; - if (!(attachment instanceof spine.RegionAttachment)) { - slotContainer.visible = false; - continue; - } - - if (attachment.rendererObject) { - if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { - var spriteName = attachment.rendererObject.name; - if (slot.currentSprite !== undefined) { - slot.currentSprite.visible = false; - } - slot.sprites = slot.sprites || {}; - if (slot.sprites[spriteName] !== undefined) { - slot.sprites[spriteName].visible = true; - } else { - var sprite = this.createSprite(slot, attachment.rendererObject); - slotContainer.addChild(sprite); - } - slot.currentSprite = slot.sprites[spriteName]; - slot.currentSpriteName = spriteName; - } - } - slotContainer.visible = true; - - var bone = slot.bone; - - slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; - slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; - slotContainer.scale.x = bone.worldScaleX; - slotContainer.scale.y = bone.worldScaleY; - - slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - - -PIXI.Spine.prototype.createSprite = function (slot, descriptor) { - var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); - sprite.scale = descriptor.scale; - sprite.rotation = descriptor.rotation; - sprite.anchor.x = sprite.anchor.y = 0.5; - - slot.sprites = slot.sprites || {}; - slot.sprites[descriptor.name] = sprite; - return sprite; -}; - -/* - * Awesome JS run time provided by EsotericSoftware - * - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -var spine = {}; - -spine.BoneData = function (name, parent) { - this.name = name; - this.parent = parent; -}; -spine.BoneData.prototype = { - length: 0, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1 -}; - -spine.SlotData = function (name, boneData) { - this.name = name; - this.boneData = boneData; -}; -spine.SlotData.prototype = { - r: 1, g: 1, b: 1, a: 1, - attachmentName: null -}; - -spine.Bone = function (boneData, parent) { - this.data = boneData; - this.parent = parent; - this.setToSetupPose(); -}; -spine.Bone.yDown = false; -spine.Bone.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - m00: 0, m01: 0, worldX: 0, // a b x - m10: 0, m11: 0, worldY: 0, // c d y - worldRotation: 0, - worldScaleX: 1, worldScaleY: 1, - updateWorldTransform: function (flipX, flipY) { - var parent = this.parent; - if (parent != null) { - this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; - this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; - this.worldScaleX = parent.worldScaleX * this.scaleX; - this.worldScaleY = parent.worldScaleY * this.scaleY; - this.worldRotation = parent.worldRotation + this.rotation; - } else { - this.worldX = this.x; - this.worldY = this.y; - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - this.worldRotation = this.rotation; - } - var radians = this.worldRotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - this.m00 = cos * this.worldScaleX; - this.m10 = sin * this.worldScaleX; - this.m01 = -sin * this.worldScaleY; - this.m11 = cos * this.worldScaleY; - if (flipX) { - this.m00 = -this.m00; - this.m01 = -this.m01; - } - if (flipY) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - if (spine.Bone.yDown) { - this.m10 = -this.m10; - this.m11 = -this.m11; - } - }, - setToSetupPose: function () { - var data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - } -}; - -spine.Slot = function (slotData, skeleton, bone) { - this.data = slotData; - this.skeleton = skeleton; - this.bone = bone; - this.setToSetupPose(); -}; -spine.Slot.prototype = { - r: 1, g: 1, b: 1, a: 1, - _attachmentTime: 0, - attachment: null, - setAttachment: function (attachment) { - this.attachment = attachment; - this._attachmentTime = this.skeleton.time; - }, - setAttachmentTime: function (time) { - this._attachmentTime = this.skeleton.time - time; - }, - getAttachmentTime: function () { - return this.skeleton.time - this._attachmentTime; - }, - setToSetupPose: function () { - var data = this.data; - this.r = data.r; - this.g = data.g; - this.b = data.b; - this.a = data.a; - - var slotDatas = this.skeleton.data.slots; - for (var i = 0, n = slotDatas.length; i < n; i++) { - if (slotDatas[i] == data) { - this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); - break; - } - } - } -}; - -spine.Skin = function (name) { - this.name = name; - this.attachments = {}; -}; -spine.Skin.prototype = { - addAttachment: function (slotIndex, name, attachment) { - this.attachments[slotIndex + ":" + name] = attachment; - }, - getAttachment: function (slotIndex, name) { - return this.attachments[slotIndex + ":" + name]; - }, - _attachAll: function (skeleton, oldSkin) { - for (var key in oldSkin.attachments) { - var colon = key.indexOf(":"); - var slotIndex = parseInt(key.substring(0, colon)); - var name = key.substring(colon + 1); - var slot = skeleton.slots[slotIndex]; - if (slot.attachment && slot.attachment.name == name) { - var attachment = this.getAttachment(slotIndex, name); - if (attachment) slot.setAttachment(attachment); - } - } - } -}; - -spine.Animation = function (name, timelines, duration) { - this.name = name; - this.timelines = timelines; - this.duration = duration; -}; -spine.Animation.prototype = { - apply: function (skeleton, time, loop) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, 1); - }, - mix: function (skeleton, time, loop, alpha) { - if (loop && this.duration != 0) time %= this.duration; - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, time, alpha); - } -}; - -spine.binarySearch = function (values, target, step) { - var low = 0; - var high = Math.floor(values.length / step) - 2; - if (high == 0) return step; - var current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } -}; -spine.linearSearch = function (values, target, step) { - for (var i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; -}; - -spine.Curves = function (frameCount) { - this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... - this.curves.length = (frameCount - 1) * 6; -}; -spine.Curves.prototype = { - setLinear: function (frameIndex) { - this.curves[frameIndex * 6] = 0/*LINEAR*/; - }, - setStepped: function (frameIndex) { - this.curves[frameIndex * 6] = -1/*STEPPED*/; - }, - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { - var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; - var subdiv_step2 = subdiv_step * subdiv_step; - var subdiv_step3 = subdiv_step2 * subdiv_step; - var pre1 = 3 * subdiv_step; - var pre2 = 3 * subdiv_step2; - var pre4 = 6 * subdiv_step2; - var pre5 = 6 * subdiv_step3; - var tmp1x = -cx1 * 2 + cx2; - var tmp1y = -cy1 * 2 + cy2; - var tmp2x = (cx1 - cx2) * 3 + 1; - var tmp2y = (cy1 - cy2) * 3 + 1; - var i = frameIndex * 6; - var curves = this.curves; - curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; - curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; - curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; - curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; - curves[i + 4] = tmp2x * pre5; - curves[i + 5] = tmp2y * pre5; - }, - getCurvePercent: function (frameIndex, percent) { - percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); - var curveIndex = frameIndex * 6; - var curves = this.curves; - var dfx = curves[curveIndex]; - if (!dfx/*LINEAR*/) return percent; - if (dfx == -1/*STEPPED*/) return 0; - var dfy = curves[curveIndex + 1]; - var ddfx = curves[curveIndex + 2]; - var ddfy = curves[curveIndex + 3]; - var dddfx = curves[curveIndex + 4]; - var dddfy = curves[curveIndex + 5]; - var x = dfx, y = dfy; - var i = 10/*BEZIER_SEGMENTS*/ - 2; - while (true) { - if (x >= percent) { - var lastX = x - dfx; - var lastY = y - dfy; - return lastY + (y - lastY) * (percent - lastX) / (x - lastX); - } - if (i == 0) break; - i--; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -}; - -spine.RotateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, angle, ... - this.frames.length = frameCount * 2; -}; -spine.RotateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, angle) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = angle; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 2]) { // Time is after last frame. - var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 2); - var lastFrameValue = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); - - var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -}; - -spine.TranslateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.TranslateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; - } -}; - -spine.ScaleTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.ScaleTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 3); - var lastFrameX = frames[frameIndex - 2]; - var lastFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; - } -}; - -spine.ColorTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, r, g, b, a, ... - this.frames.length = frameCount * 5; -}; -spine.ColorTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 5; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = r; - this.frames[frameIndex + 2] = g; - this.frames[frameIndex + 3] = b; - this.frames[frameIndex + 4] = a; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var slot = skeleton.slots[this.slotIndex]; - - if (time >= frames[frames.length - 5]) { // Time is after last frame. - var i = frames.length - 1; - slot.r = frames[i - 3]; - slot.g = frames[i - 2]; - slot.b = frames[i - 1]; - slot.a = frames[i]; - return; - } - - // Interpolate between the last frame and the current frame. - var frameIndex = spine.binarySearch(frames, time, 5); - var lastFrameR = frames[frameIndex - 4]; - var lastFrameG = frames[frameIndex - 3]; - var lastFrameB = frames[frameIndex - 2]; - var lastFrameA = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); - - var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; - var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; - var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; - var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -}; - -spine.AttachmentTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, ... - this.frames.length = frameCount; - this.attachmentNames = []; // time, ... - this.attachmentNames.length = frameCount; -}; -spine.AttachmentTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, attachmentName) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - }, - apply: function (skeleton, time, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = spine.binarySearch(frames, time, 1) - 1; - - var attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); - } -}; - -spine.SkeletonData = function () { - this.bones = []; - this.slots = []; - this.skins = []; - this.animations = []; -}; -spine.SkeletonData.prototype = { - defaultSkin: null, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - if (slots[i].name == slotName) return slot[i]; - } - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - }, - /** @return May be null. */ - findSkin: function (skinName) { - var skins = this.skins; - for (var i = 0, n = skins.length; i < n; i++) - if (skins[i].name == skinName) return skins[i]; - return null; - }, - /** @return May be null. */ - findAnimation: function (animationName) { - var animations = this.animations; - for (var i = 0, n = animations.length; i < n; i++) - if (animations[i].name == animationName) return animations[i]; - return null; - } -}; - -spine.Skeleton = function (skeletonData) { - this.data = skeletonData; - - this.bones = []; - for (var i = 0, n = skeletonData.bones.length; i < n; i++) { - var boneData = skeletonData.bones[i]; - var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; - this.bones.push(new spine.Bone(boneData, parent)); - } - - this.slots = []; - this.drawOrder = []; - for (var i = 0, n = skeletonData.slots.length; i < n; i++) { - var slotData = skeletonData.slots[i]; - var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; - var slot = new spine.Slot(slotData, this, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } -}; -spine.Skeleton.prototype = { - x: 0, y: 0, - skin: null, - r: 1, g: 1, b: 1, a: 1, - time: 0, - flipX: false, flipY: false, - /** Updates the world transform for each bone. */ - updateWorldTransform: function () { - var flipX = this.flipX; - var flipY = this.flipY; - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].updateWorldTransform(flipX, flipY); - }, - /** Sets the bones and slots to their setup pose values. */ - setToSetupPose: function () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - }, - setBonesToSetupPose: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - }, - setSlotsToSetupPose: function () { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - slots[i].setToSetupPose(i); - }, - /** @return May return null. */ - getRootBone: function () { - return this.bones.length == 0 ? null : this.bones[0]; - }, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return slots[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - }, - setSkinByName: function (skinName) { - var skin = this.data.findSkin(skinName); - if (!skin) throw "Skin not found: " + skinName; - this.setSkin(skin); - }, - /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments - * from the new skin are attached if the corresponding attachment from the old skin was attached. - * @param newSkin May be null. */ - setSkin: function (newSkin) { - if (this.skin && newSkin) newSkin._attachAll(this, this.skin); - this.skin = newSkin; - }, - /** @return May be null. */ - getAttachmentBySlotName: function (slotName, attachmentName) { - return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); - }, - /** @return May be null. */ - getAttachmentBySlotIndex: function (slotIndex, attachmentName) { - if (this.skin) { - var attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment) return attachment; - } - if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - }, - /** @param attachmentName May be null. */ - setAttachment: function (slotName, attachmentName) { - var slots = this.slots; - for (var i = 0, n = slots.size; i < n; i++) { - var slot = slots[i]; - if (slot.data.name == slotName) { - var attachment = null; - if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); - if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; - } - slot.setAttachment(attachment); - return; - } - } - throw "Slot not found: " + slotName; - }, - update: function (delta) { - time += delta; - } -}; - -spine.AttachmentType = { - region: 0 -}; - -spine.RegionAttachment = function () { - this.offset = []; - this.offset.length = 8; - this.uvs = []; - this.uvs.length = 8; -}; -spine.RegionAttachment.prototype = { - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - width: 0, height: 0, - rendererObject: null, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - setUVs: function (u, v, u2, v2, rotate) { - var uvs = this.uvs; - if (rotate) { - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v2; - uvs[4/*X3*/] = u; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v; - uvs[0/*X1*/] = u2; - uvs[1/*Y1*/] = v2; - } else { - uvs[0/*X1*/] = u; - uvs[1/*Y1*/] = v2; - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v; - uvs[4/*X3*/] = u2; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v2; - } - }, - updateOffset: function () { - var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; - var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; - var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; - var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; - var localX2 = localX + this.regionWidth * regionScaleX; - var localY2 = localY + this.regionHeight * regionScaleY; - var radians = this.rotation * Math.PI / 180; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var localXCos = localX * cos + this.x; - var localXSin = localX * sin; - var localYCos = localY * cos + this.y; - var localYSin = localY * sin; - var localX2Cos = localX2 * cos + this.x; - var localX2Sin = localX2 * sin; - var localY2Cos = localY2 * cos + this.y; - var localY2Sin = localY2 * sin; - var offset = this.offset; - offset[0/*X1*/] = localXCos - localYSin; - offset[1/*Y1*/] = localYCos + localXSin; - offset[2/*X2*/] = localXCos - localY2Sin; - offset[3/*Y2*/] = localY2Cos + localXSin; - offset[4/*X3*/] = localX2Cos - localY2Sin; - offset[5/*Y3*/] = localY2Cos + localX2Sin; - offset[6/*X4*/] = localX2Cos - localYSin; - offset[7/*Y4*/] = localYCos + localX2Sin; - }, - computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00; - var m01 = bone.m01; - var m10 = bone.m10; - var m11 = bone.m11; - var offset = this.offset; - vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; - vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; - vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; - vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; - vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; - vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; - vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; - vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; - } -} - -spine.AnimationStateData = function (skeletonData) { - this.skeletonData = skeletonData; - this.animationToMixTime = {}; -}; -spine.AnimationStateData.prototype = { - defaultMix: 0, - setMixByName: function (fromName, toName, duration) { - var from = this.skeletonData.findAnimation(fromName); - if (!from) throw "Animation not found: " + fromName; - var to = this.skeletonData.findAnimation(toName); - if (!to) throw "Animation not found: " + toName; - this.setMix(from, to, duration); - }, - setMix: function (from, to, duration) { - this.animationToMixTime[from.name + ":" + to.name] = duration; - }, - getMix: function (from, to) { - var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : this.defaultMix; - } -}; - -spine.AnimationState = function (stateData) { - this.data = stateData; - this.queue = []; -}; -spine.AnimationState.prototype = { - current: null, - previous: null, - currentTime: 0, - previousTime: 0, - currentLoop: false, - previousLoop: false, - mixTime: 0, - mixDuration: 0, - update: function (delta) { - this.currentTime += delta; - this.previousTime += delta; - this.mixTime += delta; - - if (this.queue.length > 0) { - var entry = this.queue[0]; - if (this.currentTime >= entry.delay) { - this._setAnimation(entry.animation, entry.loop); - this.queue.shift(); - } - } - }, - apply: function (skeleton) { - if (!this.current) return; - if (this.previous) { - this.previous.apply(skeleton, this.previousTime, this.previousLoop); - var alpha = this.mixTime / this.mixDuration; - if (alpha >= 1) { - alpha = 1; - this.previous = null; - } - this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else - this.current.apply(skeleton, this.currentTime, this.currentLoop); - }, - clearAnimation: function () { - this.previous = null; - this.current = null; - this.queue.length = 0; - }, - _setAnimation: function (animation, loop) { - this.previous = null; - if (animation && this.current) { - this.mixDuration = this.data.getMix(this.current, animation); - if (this.mixDuration > 0) { - this.mixTime = 0; - this.previous = this.current; - this.previousTime = this.currentTime; - this.previousLoop = this.currentLoop; - } - } - this.current = animation; - this.currentLoop = loop; - this.currentTime = 0; - }, - /** @see #setAnimation(Animation, Boolean) */ - setAnimationByName: function (animationName, loop) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.setAnimation(animation, loop); - }, - /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. - * @param animation May be null. */ - setAnimation: function (animation, loop) { - this.queue.length = 0; - this._setAnimation(animation, loop); - }, - /** @see #addAnimation(Animation, Boolean, Number) */ - addAnimationByName: function (animationName, loop, delay) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - this.addAnimation(animation, loop, delay); - }, - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimation: function (animation, loop, delay) { - var entry = {}; - entry.animation = animation; - entry.loop = loop; - - if (!delay || delay <= 0) { - var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; - if (previousAnimation != null) - delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); - else - delay = 0; - } - entry.delay = delay; - - this.queue.push(entry); - }, - /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ - isComplete: function () { - return !this.current || this.currentTime >= this.current.duration; - } -}; - -spine.SkeletonJson = function (attachmentLoader) { - this.attachmentLoader = attachmentLoader; -}; -spine.SkeletonJson.prototype = { - scale: 1, - readSkeletonData: function (root) { - var skeletonData = new spine.SkeletonData(); - - // Bones. - var bones = root["bones"]; - for (var i = 0, n = bones.length; i < n; i++) { - var boneMap = bones[i]; - var parent = null; - if (boneMap["parent"]) { - parent = skeletonData.findBone(boneMap["parent"]); - if (!parent) throw "Parent bone not found: " + boneMap["parent"]; - } - var boneData = new spine.BoneData(boneMap["name"], parent); - boneData.length = (boneMap["length"] || 0) * this.scale; - boneData.x = (boneMap["x"] || 0) * this.scale; - boneData.y = (boneMap["y"] || 0) * this.scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap["scaleX"] || 1; - boneData.scaleY = boneMap["scaleY"] || 1; - skeletonData.bones.push(boneData); - } - - // Slots. - var slots = root["slots"]; - for (var i = 0, n = slots.length; i < n; i++) { - var slotMap = slots[i]; - var boneData = skeletonData.findBone(slotMap["bone"]); - if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; - var slotData = new spine.SlotData(slotMap["name"], boneData); - - var color = slotMap["color"]; - if (color) { - slotData.r = spine.SkeletonJson.toColor(color, 0); - slotData.g = spine.SkeletonJson.toColor(color, 1); - slotData.b = spine.SkeletonJson.toColor(color, 2); - slotData.a = spine.SkeletonJson.toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - - skeletonData.slots.push(slotData); - } - - // Skins. - var skins = root["skins"]; - for (var skinName in skins) { - if (!skins.hasOwnProperty(skinName)) continue; - var skinMap = skins[skinName]; - var skin = new spine.Skin(skinName); - for (var slotName in skinMap) { - if (!skinMap.hasOwnProperty(slotName)) continue; - var slotIndex = skeletonData.findSlotIndex(slotName); - var slotEntry = skinMap[slotName]; - for (var attachmentName in slotEntry) { - if (!slotEntry.hasOwnProperty(attachmentName)) continue; - var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); - if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - - // Animations. - var animations = root["animations"]; - for (var animationName in animations) { - if (!animations.hasOwnProperty(animationName)) continue; - this.readAnimation(animationName, animations[animationName], skeletonData); - } - - return skeletonData; - }, - readAttachment: function (skin, name, map) { - name = map["name"] || name; - - var type = spine.AttachmentType[map["type"] || "region"]; - - if (type == spine.AttachmentType.region) { - var attachment = new spine.RegionAttachment(); - attachment.x = (map["x"] || 0) * this.scale; - attachment.y = (map["y"] || 0) * this.scale; - attachment.scaleX = map["scaleX"] || 1; - attachment.scaleY = map["scaleY"] || 1; - attachment.rotation = map["rotation"] || 0; - attachment.width = (map["width"] || 32) * this.scale; - attachment.height = (map["height"] || 32) * this.scale; - attachment.updateOffset(); - - attachment.rendererObject = {}; - attachment.rendererObject.name = name; - attachment.rendererObject.scale = {}; - attachment.rendererObject.scale.x = attachment.scaleX; - attachment.rendererObject.scale.y = attachment.scaleY; - attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; - return attachment; - } - - throw "Unknown attachment type: " + type; - }, - - readAnimation: function (name, map, skeletonData) { - var timelines = []; - var duration = 0; - - var bones = map["bones"]; - for (var boneName in bones) { - if (!bones.hasOwnProperty(boneName)) continue; - var boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw "Bone not found: " + boneName; - var boneMap = bones[boneName]; - - for (var timelineName in boneMap) { - if (!boneMap.hasOwnProperty(timelineName)) continue; - var values = boneMap[timelineName]; - if (timelineName == "rotate") { - var timeline = new spine.RotateTimeline(values.length); - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - - } else if (timelineName == "translate" || timelineName == "scale") { - var timeline; - var timelineScale = 1; - if (timelineName == "scale") - timeline = new spine.ScaleTimeline(values.length); - else { - timeline = new spine.TranslateTimeline(values.length); - timelineScale = this.scale; - } - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var x = (valueMap["x"] || 0) * timelineScale; - var y = (valueMap["y"] || 0) * timelineScale; - timeline.setFrame(frameIndex, valueMap["time"], x, y); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - - } else - throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; - } - } - var slots = map["slots"]; - for (var slotName in slots) { - if (!slots.hasOwnProperty(slotName)) continue; - var slotMap = slots[slotName]; - var slotIndex = skeletonData.findSlotIndex(slotName); - - for (var timelineName in slotMap) { - if (!slotMap.hasOwnProperty(timelineName)) continue; - var values = slotMap[timelineName]; - if (timelineName == "color") { - var timeline = new spine.ColorTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var color = valueMap["color"]; - var r = spine.SkeletonJson.toColor(color, 0); - var g = spine.SkeletonJson.toColor(color, 1); - var b = spine.SkeletonJson.toColor(color, 2); - var a = spine.SkeletonJson.toColor(color, 3); - timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); - - } else if (timelineName == "attachment") { - var timeline = new spine.AttachmentTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - - } else - throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; - } - } - skeletonData.animations.push(new spine.Animation(name, timelines, duration)); - } -}; -spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { - var curve = valueMap["curve"]; - if (!curve) return; - if (curve == "stepped") - timeline.curves.setStepped(frameIndex); - else if (curve instanceof Array) - timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); -}; -spine.SkeletonJson.toColor = function (hexString, colorIndex) { - if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; - return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; -}; - -spine.Atlas = function (atlasText, textureLoader) { - this.textureLoader = textureLoader; - this.pages = []; - this.regions = []; - - var reader = new spine.AtlasReader(atlasText); - var tuple = []; - tuple.length = 4; - var page = null; - while (true) { - var line = reader.readLine(); - if (line == null) break; - line = reader.trim(line); - if (line.length == 0) - page = null; - else if (!page) { - page = new spine.AtlasPage(); - page.name = line; - - page.format = spine.Atlas.Format[reader.readValue()]; - - reader.readTuple(tuple); - page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; - page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; - - var direction = reader.readValue(); - page.uWrap = spine.Atlas.TextureWrap.clampToEdge; - page.vWrap = spine.Atlas.TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "y") - page.vWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; - - textureLoader.load(page, line); - - this.pages.push(page); - - } else { - var region = new spine.AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x = parseInt(tuple[0]); - var y = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width = parseInt(tuple[0]); - var height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - this.regions.push(region); - } - } -}; -spine.Atlas.prototype = { - findRegion: function (name) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - }, - dispose: function () { - var pages = this.pages; - for (var i = 0, n = pages.length; i < n; i++) - this.textureLoader.unload(pages[i].rendererObject); - }, - updateUVs: function (page) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) { - var region = regions[i]; - if (region.page != page) continue; - region.u = region.x / page.width; - region.v = region.y / page.height; - if (region.rotate) { - region.u2 = (region.x + region.height) / page.width; - region.v2 = (region.y + region.width) / page.height; - } else { - region.u2 = (region.x + region.width) / page.width; - region.v2 = (region.y + region.height) / page.height; - } - } - } -}; - -spine.Atlas.Format = { - alpha: 0, - intensity: 1, - luminanceAlpha: 2, - rgb565: 3, - rgba4444: 4, - rgb888: 5, - rgba8888: 6 -}; - -spine.Atlas.TextureFilter = { - nearest: 0, - linear: 1, - mipMap: 2, - mipMapNearestNearest: 3, - mipMapLinearNearest: 4, - mipMapNearestLinear: 5, - mipMapLinearLinear: 6 -}; - -spine.Atlas.TextureWrap = { - mirroredRepeat: 0, - clampToEdge: 1, - repeat: 2 -}; - -spine.AtlasPage = function () {}; -spine.AtlasPage.prototype = { - name: null, - format: null, - minFilter: null, - magFilter: null, - uWrap: null, - vWrap: null, - rendererObject: null, - width: 0, - height: 0 -}; - -spine.AtlasRegion = function () {}; -spine.AtlasRegion.prototype = { - page: null, - name: null, - x: 0, y: 0, - width: 0, height: 0, - u: 0, v: 0, u2: 0, v2: 0, - offsetX: 0, offsetY: 0, - originalWidth: 0, originalHeight: 0, - index: 0, - rotate: false, - splits: null, - pads: null, -}; - -spine.AtlasReader = function (text) { - this.lines = text.split(/\r\n|\r|\n/); -}; -spine.AtlasReader.prototype = { - index: 0, - trim: function (value) { - return value.replace(/^\s+|\s+$/g, ""); - }, - readLine: function () { - if (this.index >= this.lines.length) return null; - return this.lines[this.index++]; - }, - readValue: function () { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - return this.trim(line.substring(colon + 1)); - }, - /** Returns the number of tuple values read (2 or 4). */ - readTuple: function (tuple) { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - var i = 0, lastMatch= colon + 1; - for (; i < 3; i++) { - var comma = line.indexOf(",", lastMatch); - if (comma == -1) { - if (i == 0) throw "Invalid line: " + line; - break; - } - tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = this.trim(line.substring(lastMatch)); - return i + 1; - } -} - -spine.AtlasAttachmentLoader = function (atlas) { - this.atlas = atlas; -} -spine.AtlasAttachmentLoader.prototype = { - newAttachment: function (skin, type, name) { - switch (type) { - case spine.AttachmentType.region: - var region = this.atlas.findRegion(name); - if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; - var attachment = new spine.RegionAttachment(name); - attachment.rendererObject = region; - attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - throw "Unknown attachment type: " + type; - } -} - -PIXI.AnimCache = {}; -spine.Bone.yDown = true; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - - -/** - * This object is one that will allow you to specify custom rendering functions based on render type - * - * @class CustomRenderable - * @extends DisplayObject - * @constructor - */ -PIXI.CustomRenderable = function() -{ - PIXI.DisplayObject.call( this ); - - this.renderable = true; -} - -// constructor -PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); -PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; - -/** - * If this object is being rendered by a CanvasRenderer it will call this callback - * - * @method renderCanvas - * @param renderer {CanvasRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback to initialize - * - * @method initWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.initWebGL = function(renderer) -{ - // override! -} - -/** - * If this object is being rendered by a WebGLRenderer it will call this callback - * - * @method renderWebGL - * @param renderer {WebGLRenderer} The renderer instance - */ -PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) -{ - // not sure if both needed? but ya have for now! - // override! -} - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; - -/** - * A texture stores the information that represents an image. All textures have a base texture - * - * @class BaseTexture - * @uses EventTarget - * @constructor - * @param source {String} the source object (image or canvas) - */ -PIXI.BaseTexture = function(source) -{ - PIXI.EventTarget.call( this ); - - /** - * [read-only] The width of the base texture set when the image has loaded - * - * @property width - * @type Number - * @readOnly - */ - this.width = 100; - - /** - * [read-only] The height of the base texture set when the image has loaded - * - * @property height - * @type Number - * @readOnly - */ - this.height = 100; - - /** - * [read-only] Describes if the base texture has loaded or not - * - * @property hasLoaded - * @type Boolean - * @readOnly - */ - this.hasLoaded = false; - - /** - * The source that is loaded to create the texture - * - * @property source - * @type Image - */ - this.source = source; - - if(!source)return; - - if(this.source instanceof Image || this.source instanceof HTMLImageElement) - { - if(this.source.complete) - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - else - { - - var scope = this; - this.source.onload = function(){ - - scope.hasLoaded = true; - scope.width = scope.source.width; - scope.height = scope.source.height; - - // add it to somewhere... - PIXI.texturesToUpdate.push(scope); - scope.dispatchEvent( { type: 'loaded', content: scope } ); - } - // this.image.src = imageUrl; - } - } - else - { - this.hasLoaded = true; - this.width = this.source.width; - this.height = this.source.height; - - PIXI.texturesToUpdate.push(this); - } - - this._powerOf2 = false; -} - -PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; - -/** - * Destroys this base texture - * - * @method destroy - */ -PIXI.BaseTexture.prototype.destroy = function() -{ - if(this.source instanceof Image) - { - this.source.src = null; - } - this.source = null; - PIXI.texturesToDestroy.push(this); -} - -/** - * Helper function that returns a base texture based on an image url - * If the image is not in the base texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @return BaseTexture - */ -PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) -{ - var baseTexture = PIXI.BaseTextureCache[imageUrl]; - if(!baseTexture) - { - // new Image() breaks tex loading in some versions of Chrome. - // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); - if (crossorigin) - { - image.crossOrigin = ''; - } - image.src = imageUrl; - baseTexture = new PIXI.BaseTexture(image); - PIXI.BaseTextureCache[imageUrl] = baseTexture; - } - - return baseTexture; -} - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -PIXI.TextureCache = {}; -PIXI.FrameCache = {}; - -/** - * A texture stores the information that represents an image or part of an image. It cannot be added - * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used - * - * @class Texture - * @uses EventTarget - * @constructor - * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frame {Rectangle} The rectangle frame of the texture to show - */ -PIXI.Texture = function(baseTexture, frame) -{ - PIXI.EventTarget.call( this ); - - if(!frame) - { - this.noFrame = true; - frame = new PIXI.Rectangle(0,0,1,1); - } - - if(baseTexture instanceof PIXI.Texture) - baseTexture = baseTexture.baseTexture; - - /** - * The base texture of this texture - * - * @property baseTexture - * @type BaseTexture - */ - this.baseTexture = baseTexture; - - /** - * The frame specifies the region of the base texture that this texture uses - * - * @property frame - * @type Rectangle - */ - this.frame = frame; - - /** - * The trim point - * - * @property trim - * @type Point - */ - this.trim = new PIXI.Point(); - - this.scope = this; - - if(baseTexture.hasLoaded) - { - if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - //console.log(frame) - - this.setFrame(frame); - } - else - { - var scope = this; - baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); - } -} - -PIXI.Texture.prototype.constructor = PIXI.Texture; - -/** - * Called when the base texture is loaded - * - * @method onBaseTextureLoaded - * @param event - * @private - */ -PIXI.Texture.prototype.onBaseTextureLoaded = function(event) -{ - var baseTexture = this.baseTexture; - baseTexture.removeEventListener( 'loaded', this.onLoaded ); - - if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); - this.noFrame = false; - this.width = this.frame.width; - this.height = this.frame.height; - - this.scope.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Destroys this texture - * - * @method destroy - * @param destroyBase {Boolean} Whether to destroy the base texture as well - */ -PIXI.Texture.prototype.destroy = function(destroyBase) -{ - if(destroyBase)this.baseTexture.destroy(); -} - -/** - * Specifies the rectangle region of the baseTexture - * - * @method setFrame - * @param frame {Rectangle} The frame of the texture to set it to - */ -PIXI.Texture.prototype.setFrame = function(frame) -{ - this.frame = frame; - this.width = frame.width; - this.height = frame.height; - - 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); - } - - this.updateFrame = true; - - PIXI.Texture.frameUpdates.push(this); - //this.dispatchEvent( { type: 'update', content: this } ); -} - -/** - * Helper function that returns a texture based on an image url - * If the image is not in the texture cache it will be created and loaded - * - * @static - * @method fromImage - * @param imageUrl {String} The image url of the texture - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - * @return Texture - */ -PIXI.Texture.fromImage = function(imageUrl, crossorigin) -{ - var texture = PIXI.TextureCache[imageUrl]; - - if(!texture) - { - texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); - PIXI.TextureCache[imageUrl] = texture; - } - - return texture; -} - -/** - * Helper function that returns a texture based on a frame id - * If the frame id is not in the texture cache an error will be thrown - * - * @static - * @method fromFrame - * @param frameId {String} The frame id of the texture - * @return Texture - */ -PIXI.Texture.fromFrame = function(frameId) -{ - var texture = PIXI.TextureCache[frameId]; - if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); - return texture; -} - -/** - * Helper function that returns a texture based on a canvas element - * If the canvas is not in the texture cache it will be created and loaded - * - * @static - * @method fromCanvas - * @param canvas {Canvas} The canvas element source of the texture - * @return Texture - */ -PIXI.Texture.fromCanvas = function(canvas) -{ - var baseTexture = new PIXI.BaseTexture(canvas); - return new PIXI.Texture(baseTexture); -} - - -/** - * Adds a texture to the textureCache. - * - * @static - * @method addTextureToCache - * @param texture {Texture} - * @param id {String} the id that the texture will be stored against. - */ -PIXI.Texture.addTextureToCache = function(texture, id) -{ - PIXI.TextureCache[id] = texture; -} - -/** - * Remove a texture from the textureCache. - * - * @static - * @method removeTextureFromCache - * @param id {String} the id of the texture to be removed - * @return {Texture} the texture that was removed - */ -PIXI.Texture.removeTextureFromCache = function(id) -{ - var texture = PIXI.TextureCache[id] - PIXI.TextureCache[id] = null; - return texture; -} - -// this is more for webGL.. it contains updated frames.. -PIXI.Texture.frameUpdates = []; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. - - __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. - Otherwise black rectangles will be drawn instead. - - RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: - - var renderTexture = new PIXI.RenderTexture(800, 600); - var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); - sprite.position.x = 800/2; - sprite.position.y = 600/2; - sprite.anchor.x = 0.5; - sprite.anchor.y = 0.5; - renderTexture.render(sprite); - - Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: - - var doc = new PIXI.DisplayObjectContainer(); - doc.addChild(sprite); - renderTexture.render(doc); // Renders to center of renderTexture - - @class RenderTexture - @extends Texture - @constructor - @param width {Number} The width of the render texture - @param height {Number} The height of the render texture - */ -PIXI.RenderTexture = function(width, height) -{ - PIXI.EventTarget.call( this ); - - this.width = width || 100; - this.height = height || 100; - - this.indetityMatrix = PIXI.mat3.create(); - - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - if(PIXI.gl) - { - this.initWebGL(); - } - else - { - this.initCanvas(); - } -} - -PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); -PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; - -/** - * Initializes the webgl data for this texture - * - * @method initWebGL - * @private - */ -PIXI.RenderTexture.prototype.initWebGL = function() -{ - var gl = PIXI.gl; - this.glFramebuffer = gl.createFramebuffer(); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - this.glFramebuffer.width = this.width; - this.glFramebuffer.height = this.height; - - this.baseTexture = new PIXI.BaseTexture(); - - this.baseTexture.width = this.width; - this.baseTexture.height = this.height; - - this.baseTexture._glTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - - this.baseTexture.isRender = true; - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); - - // create a projection matrix.. - this.projection = new PIXI.Point(this.width/2 , -this.height/2); - - // set the correct render function.. - this.render = this.renderWebGL; -} - - -PIXI.RenderTexture.prototype.resize = function(width, height) -{ - - this.width = width; - this.height = height; - - if(PIXI.gl) - { - this.projection.x = this.width/2 - this.projection.y = -this.height/2; - - var gl = PIXI.gl; - gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - } - else - { - - this.frame.width = this.width - this.frame.height = this.height; - this.renderer.resize(this.width, this.height); - } -} - -/** - * Initializes the canvas data for this texture - * - * @method initCanvas - * @private - */ -PIXI.RenderTexture.prototype.initCanvas = function() -{ - this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); - - this.baseTexture = new PIXI.BaseTexture(this.renderer.view); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - - this.render = this.renderCanvas; -} - -/** - * This function will draw the display object to the texture. - * - * @method renderWebGL - * @param displayObject {DisplayObject} The display object to render this texture on - * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn - * @private - */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) -{ - var gl = PIXI.gl; - - // enable the alpha color mask.. - gl.colorMask(true, true, true, true); - - gl.viewport(0, 0, this.width, this.height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); - - if(clear) - { - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } - - // THIS WILL MESS WITH HIT TESTING! - var children = displayObject.children; - - //TODO -? create a new one??? dont think so! - var originalWorldTransform = displayObject.worldTransform; - displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; - // modify to flip... - displayObject.worldTransform[4] = -1; - displayObject.worldTransform[5] = this.projection.y * -2; - - if(position) - { - displayObject.worldTransform[2] = position.x; - displayObject.worldTransform[5] -= position.y; - } - - PIXI.visibleCount++; - displayObject.vcount = PIXI.visibleCount; - - for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded - * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported - * sprite sheet data formats only include "JSON" at this time. Supported bitmap font - * data formats include "xml" and "fnt". - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.AssetLoader = function(assetURLs, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The array of asset URLs that are going to be loaded - * - * @property assetURLs - * @type Array - */ - this.assetURLs = assetURLs; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * Maps file extension to loader types - * - * @property loadersByType - * @type Object - */ - this.loadersByType = { - "jpg": PIXI.ImageLoader, - "jpeg": PIXI.ImageLoader, - "png": PIXI.ImageLoader, - "gif": PIXI.ImageLoader, - "json": PIXI.JsonLoader, - "anim": PIXI.SpineLoader, - "xml": PIXI.BitmapFontLoader, - "fnt": PIXI.BitmapFontLoader - }; - - -}; - -/** - * Fired when an item has loaded - * @event onProgress - */ - -/** - * Fired when all the assets have loaded - * @event onComplete - */ - -// constructor -PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; - -/** - * Starts loading the assets sequentially - * - * @method load - */ -PIXI.AssetLoader.prototype.load = function() -{ - var scope = this; - - this.loadCount = this.assetURLs.length; - - for (var i=0; i < this.assetURLs.length; i++) - { - var fileName = this.assetURLs[i]; - var fileType = fileName.split(".").pop().toLowerCase(); - - var loaderClass = this.loadersByType[fileType]; - if(!loaderClass) - throw new Error(fileType + " is an unsupported file type"); - - var loader = new loaderClass(fileName, this.crossorigin); - - loader.addEventListener("loaded", function() - { - scope.onAssetLoaded(); - }); - loader.load(); - } -}; - -/** - * Invoked after each file is loaded - * - * @method onAssetLoaded - * @private - */ -PIXI.AssetLoader.prototype.onAssetLoaded = function() -{ - this.loadCount--; - this.dispatchEvent({type: "onProgress", content: this}); - if(this.onProgress) this.onProgress(); - - if(this.loadCount == 0) - { - this.dispatchEvent({type: "onComplete", content: this}); - if(this.onComplete) this.onComplete(); - } -}; - - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The json file loader is used to load in JSON data and parsing it - * When loaded this class will dispatch a "loaded" event - * If load failed this class will dispatch a "error" event - * - * @class JsonLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.JsonLoader = function (url, crossorigin) { - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * [read-only] Whether the data has loaded yet - * - * @property loaded - * @type Boolean - * @readOnly - */ - this.loaded = false; - -}; - -// constructor -PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; - -/** - * Loads the JSON data - * - * @method load - */ -PIXI.JsonLoader.prototype.load = function () { - this.ajaxRequest = new AjaxRequest(); - var scope = this; - this.ajaxRequest.onreadystatechange = function () { - scope.onJSONLoaded(); - }; - - this.ajaxRequest.open("GET", this.url, true); - if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); - this.ajaxRequest.send(null); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.JsonLoader.prototype.onJSONLoaded = function () { - if (this.ajaxRequest.readyState == 4) { - if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { - this.json = JSON.parse(this.ajaxRequest.responseText); - - if(this.json.frames) - { - // sprite sheet - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); - - } - else if(this.json.bones) - { - // spine animation - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - PIXI.AnimCache[this.url] = skeletonData; - this.onLoaded(); - } - else - { - this.onLoaded(); - } - } - else - { - this.onError(); - } - } -}; - -/** - * Invoke when json file loaded - * - * @method onLoaded - * @private - */ -PIXI.JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * Invoke when error occured - * - * @method onError - * @private - */ -PIXI.JsonLoader.prototype.onError = function () { - this.dispatchEvent({ - type: "error", - content: this - }); -}; -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The sprite sheet loader is used to load in JSON sprite sheet data - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format - * There is a free version so thats nice, although the paid version is great value for money. - * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * This loader will also load the image file that the Spritesheet points to as well as the data. - * When loaded this class will dispatch a "loaded" event - * - * @class SpriteSheetLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ - -PIXI.SpriteSheetLoader = function (url, crossorigin) { - /* - * i use texture packer to load the assets.. - * http://www.codeandweb.com/texturepacker - * make sure to set the format as "JSON" - */ - PIXI.EventTarget.call(this); - - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @property crossorigin - * @type Boolean - */ - this.crossorigin = crossorigin; - - /** - * [read-only] The base url of the bitmap font data - * - * @property baseUrl - * @type String - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ""); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = null; - - /** - * The frames of the sprite sheet - * - * @property frames - * @type Object - */ - this.frames = {}; -}; - -// constructor -PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; - -/** - * This will begin loading the JSON file - * - * @method load - */ -PIXI.SpriteSheetLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); - jsonLoader.addEventListener("loaded", function (event) { - scope.json = event.content.json; - scope.onJSONLoaded(); - }); - jsonLoader.load(); -}; - -/** - * Invoke when JSON file is loaded - * - * @method onJSONLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { - var scope = this; - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener("loaded", function (event) { - scope.onLoaded(); - }); - - for (var i in frameData) { - var rect = frameData[i].frame; - if (rect) { - PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - //var realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; - PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) - // calculate the offset! - } - } - } - - image.load(); -}; -/** - * Invoke when all files are loaded (json and texture) - * - * @method onLoaded - * @private - */ -PIXI.SpriteSheetLoader.prototype.onLoaded = function () { - this.dispatchEvent({ - type: "loaded", - content: this - }); -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") - * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() - * When loaded this class will dispatch a 'loaded' event - * - * @class ImageLoader - * @uses EventTarget - * @constructor - * @param url {String} The url of the image - * @param crossorigin {Boolean} Whether requests should be treated as crossorigin - */ -PIXI.ImageLoader = function(url, crossorigin) -{ - PIXI.EventTarget.call(this); - - /** - * The texture being loaded - * - * @property texture - * @type Texture - */ - this.texture = PIXI.Texture.fromImage(url, crossorigin); - - /** - * if the image is loaded with loadFramedSpriteSheet - * frames will contain the sprite sheet frames - * - */ - this.frames = []; -}; - -// constructor -PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; - -/** - * Loads image or takes it from cache - * - * @method load - */ -PIXI.ImageLoader.prototype.load = function() -{ - if(!this.texture.baseTexture.hasLoaded) - { - var scope = this; - this.texture.baseTexture.addEventListener("loaded", function() - { - scope.onLoaded(); - }); - } - else - { - this.onLoaded(); - } -}; - -/** - * Invoked when image file is loaded or it is already cached and ready to use - * - * @method onLoaded - * @private - */ -PIXI.ImageLoader.prototype.onLoaded = function() -{ - this.dispatchEvent({type: "loaded", content: this}); -}; - -/** - * Loads image and split it to uniform sized frames - * - * - * @method loadFramedSpriteSheet - * @param frameWidth {Number} with of each frame - * @param frameHeight {Number} height of each frame - * @param textureName {String} if given, the frames will be cached in - format - */ -PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) -{ - this.frames = []; - var cols = Math.floor(this.texture.width / frameWidth); - var rows = Math.floor(this.texture.height / frameHeight); - - var i=0; - for (var y=0; y= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +} + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + + +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array)) + points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(typeof points[0] === 'number') { + var p = []; + for(var i = 0, il = points.length; i < il; i+=2) { + p.push( + new PIXI.Point(points[i], points[i + 1]) + ); + } + + points = p; + } + + this.points = points; +} + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = []; + for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +} + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; + +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayobjects + * + * @class Circle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +} + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +} + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + + +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayobjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +} + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + //and a radius of 0.5 + var normx = ((x - this.x) / this.width) - 0.5, + normy = ((y - this.y) / this.height) - 0.5; + + normx *= normx; + normy *= normy; + + return (normx + normy < 0.25); +} + +PIXI.Ellipse.getBounds = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +} + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; + + + +/* + * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV + * you both rock! + */ + +function determineMatrixArrayType() { + PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + return PIXI.Matrix; +} + +determineMatrixArrayType(); + +PIXI.mat3 = {}; + +PIXI.mat3.create = function() +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat3.identity = function(matrix) +{ + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat4 = {}; + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat3.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[3], a11 = mat[4], a12 = mat[5], + a20 = mat[6], a21 = mat[7], a22 = mat[8], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], + b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], + b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22; + + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; + dest[4] = b10 * a01 + b11 * a11 + b12 * a21; + dest[5] = b10 * a02 + b11 * a12 + b12 * a22; + + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; + dest[7] = b20 * a01 + b21 * a11 + b22 * a21; + dest[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return dest; +} + +PIXI.mat3.clone = function(mat) +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = mat[0]; + matrix[1] = mat[1]; + matrix[2] = mat[2]; + matrix[3] = mat[3]; + matrix[4] = mat[4]; + matrix[5] = mat[5]; + matrix[6] = mat[6]; + matrix[7] = mat[7]; + matrix[8] = mat[8]; + + return matrix; +} + +PIXI.mat3.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +} + +PIXI.mat3.toMat4 = function (mat, dest) +{ + if (!dest) { dest = PIXI.mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +} + + +///// + + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat4.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) + { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +} + +PIXI.mat4.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; + var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; + var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + // Cache only the current line of the second matrix + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[4]; + b1 = mat2[5]; + b2 = mat2[6]; + b3 = mat2[7]; + dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[8]; + b1 = mat2[9]; + b2 = mat2[10]; + b3 = mat2[11]; + dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[12]; + b1 = mat2[13]; + b2 = mat2[14]; + b3 = mat2[15]; + dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + return dest; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The base class for all objects that are rendered on the screen. + * + * @class DisplayObject + * @constructor + */ +PIXI.DisplayObject = function() +{ + this.last = this; + this.first = this; + /** + * The coordinate of the object relative to the local coordinates of the parent. + * + * @property position + * @type Point + */ + this.position = new PIXI.Point(); + + /** + * The scale factor of the object. + * + * @property scale + * @type Point + */ + this.scale = new PIXI.Point(1,1);//{x:1, y:1}; + + /** + * The pivot point of the displayObject that it rotates around + * + * @property pivot + * @type Point + */ + this.pivot = new PIXI.Point(0,0); + + /** + * The rotation of the object in radians. + * + * @property rotation + * @type Number + */ + this.rotation = 0; + + /** + * The opacity of the object. + * + * @property alpha + * @type Number + */ + this.alpha = 1; + + /** + * The visibility of the object. + * + * @property visible + * @type Boolean + */ + this.visible = true; + + /** + * This is the defined area that will pick up mouse / touch events. It is null by default. + * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) + * + * @property hitArea + * @type Rectangle|Circle|Ellipse|Polygon + */ + this.hitArea = null; + + /** + * This is used to indicate if the displayObject should display a mouse hand cursor on rollover + * + * @property buttonMode + * @type Boolean + */ + this.buttonMode = false; + + /** + * Can this object be rendered + * + * @property renderable + * @type Boolean + */ + this.renderable = false; + + /** + * [read-only] The display object container that contains this display object. + * + * @property parent + * @type DisplayObjectContainer + * @readOnly + */ + this.parent = null; + + /** + * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. + * + * @property stage + * @type Stage + * @readOnly + */ + this.stage = null; + + /** + * [read-only] The multiplied alpha of the displayobject + * + * @property worldAlpha + * @type Number + * @readOnly + */ + this.worldAlpha = 1; + + /** + * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property + * + * @property _interactive + * @type Boolean + * @readOnly + * @private + */ + this._interactive = false; + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [read-only] Current transform of the object locally + * + * @property localTransform + * @type Mat3 + * @readOnly + * @private + */ + this.localTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [NYI] Unkown + * + * @property color + * @type Array<> + * @private + */ + this.color = []; + + /** + * [NYI] Holds whether or not this object is dynamic, for rendering optimization + * + * @property dynamic + * @type Boolean + * @private + */ + this.dynamic = true; + + // chach that puppy! + this._sr = 0; + this._cr = 1; + + + this.filterArea = new PIXI.Rectangle(0,0,1,1); + + /* + * MOUSE Callbacks + */ + + /** + * A callback that is used when the users clicks on the displayObject with their mouse + * @method click + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user clicks the mouse down over the sprite + * @method mousedown + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject + * for this callback to be fired the mouse must have been pressed down over the displayObject + * @method mouseup + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject + * for this callback to be fired, The touch must have started over the displayObject + * @method mouseupoutside + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse rolls over the displayObject + * @method mouseover + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse leaves the displayObject + * @method mouseout + * @param interactionData {InteractionData} + */ + + + /* + * TOUCH Callbacks + */ + + /** + * A callback that is used when the users taps on the sprite with their finger + * basically a touch version of click + * @method tap + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user touch's over the displayObject + * @method touchstart + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases a touch over the displayObject + * @method touchend + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the touch that was over the displayObject + * for this callback to be fired, The touch must have started over the sprite + * @method touchendoutside + * @param interactionData {InteractionData} + */ +} + +// constructor +PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; + +/** + * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default + * Instead of using this function you can now simply set the interactive property to true or false + * + * @method setInteractive + * @param interactive {Boolean} + * @deprecated Simply set the `interactive` property directly + */ +PIXI.DisplayObject.prototype.setInteractive = function(interactive) +{ + this.interactive = interactive; +} + +/** + * Indicates if the sprite will have touch and mouse interactivity. It is false by default + * + * @property interactive + * @type Boolean + * @default false + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { + get: function() { + return this._interactive; + }, + set: function(value) { + this._interactive = value; + + // TODO more to be done here.. + // need to sort out a re-crawl! + if(this.stage)this.stage.dirty = true; + } +}); + +/** + * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. + * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. + * To remove a mask, set this property to null. + * + * @property mask + * @type Graphics + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { + get: function() { + return this._mask; + }, + set: function(value) { + + + if(value) + { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. + * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. + * To remove filters simply set this property to 'null' + * @property filters + * @type Array An array of filters + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + if(value) + { + if(this._filters)this.removeFilter(this._filters); + this.addFilter(value); + + // now put all the passes in one place.. + var passes = []; + for (var i = 0; i < value.length; i++) + { + var filterPasses = value[i].passes; + for (var j = 0; j < filterPasses.length; j++) + { + passes.push(filterPasses[j]); + }; + }; + + value.start.filterPasses = passes; + } + else + { + if(this._filters)this.removeFilter(this._filters); + } + + this._filters = value; + + + + + } +}); + +/* + * Adds a filter to this displayObject + * + * @method addFilter + * @param mask {Graphics} the graphics object to use as a filter + * @private + */ +PIXI.DisplayObject.prototype.addFilter = function(data) +{ + //if(this.filter)return; + //this.filter = true; +// data[0].target = this; + + + // insert a filter block.. + // TODO Onject pool thease bad boys.. + var start = new PIXI.FilterBlock(); + var end = new PIXI.FilterBlock(); + + data.start = start; + data.end = end; + + start.data = data; + end.data = data; + + start.first = start.last = this; + end.first = end.last = this; + + start.open = true; + + start.target = this; + + /* + * insert start + */ + + var childFirst = start + var childLast = start + var nextObject; + var previousObject; + + previousObject = this.first._iPrev; + + if(previousObject) + { + nextObject = previousObject._iNext; + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + } + else + { + nextObject = this; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + + // now insert the end filter block.. + + /* + * insert end filter + */ + var childFirst = end + var childLast = end + var nextObject = null; + var previousObject = null; + + previousObject = this.last; + nextObject = previousObject._iNext; + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + var updateLast = this; + + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = end; + } + updateLast = updateLast.parent; + } + + this.first = start; + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.addFilterBlocks(start, end); + } + +} + +/* + * Removes the filter to this displayObject + * + * @method removeFilter + * @private + */ +PIXI.DisplayObject.prototype.removeFilter = function(data) +{ + //if(!this.filter)return; + //this.filter = false; + // console.log("YUOIO") + // modify the list.. + var startBlock = data.start; + + + var nextObject = startBlock._iNext; + var previousObject = startBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + if(previousObject)previousObject._iNext = nextObject; + + this.first = startBlock._iNext; + + // remove the end filter + var lastBlock = data.end; + + var nextObject = lastBlock._iNext; + var previousObject = lastBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + // this is always true too! + var tempLast = lastBlock._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == lastBlock) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); + } +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObject.prototype.updateTransform = function() +{ + // TODO OPTIMIZE THIS!! with dirty + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + var localTransform = this.localTransform; + var parentTransform = this.parent.worldTransform; + var worldTransform = this.worldTransform; + //console.log(localTransform) + localTransform[0] = this._cr * this.scale.x; + localTransform[1] = -this._sr * this.scale.y + localTransform[3] = this._sr * this.scale.x; + localTransform[4] = this._cr * this.scale.y; + + // TODO --> do we even need a local matrix??? + + var px = this.pivot.x; + var py = this.pivot.y; + + // Cache the matrix values (makes for huge speed increases!) + var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], + a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], + + b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], + b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; + + localTransform[2] = a02 + localTransform[5] = a12 + + worldTransform[0] = b00 * a00 + b01 * a10; + worldTransform[1] = b00 * a01 + b01 * a11; + worldTransform[2] = b00 * a02 + b01 * a12 + b02; + + worldTransform[3] = b10 * a00 + b11 * a10; + worldTransform[4] = b10 * a01 + b11 * a11; + worldTransform[5] = b10 * a02 + b11 * a12 + b12; + + // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! + // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); + this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; + +} + +PIXI.visibleCount = 0; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A DisplayObjectContainer represents a collection of display objects. + * It is the base class of all display objects that act as a container for other objects. + * + * @class DisplayObjectContainer + * @extends DisplayObject + * @constructor + */ +PIXI.DisplayObjectContainer = function() +{ + PIXI.DisplayObject.call( this ); + + /** + * [read-only] The of children of this container. + * + * @property children + * @type Array + * @readOnly + */ + this.children = []; +} + +// constructor +PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; + +/** + * Adds a child to the container. + * + * @method addChild + * @param child {DisplayObject} The DisplayObject to add to the container + */ +PIXI.DisplayObjectContainer.prototype.addChild = function(child) +{ + if(child.parent != undefined) + { + + //// COULD BE THIS??? + child.parent.removeChild(child); + // return; + } + + child.parent = this; + + this.children.push(child); + + // update the stage refference.. + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // LINKED LIST // + + // modify the list.. + var childFirst = child.first + var childLast = child.last; + var nextObject; + var previousObject; + + // this could be wrong if there is a filter?? + if(this._filters || this._mask) + { + previousObject = this.last._iPrev; + } + else + { + previousObject = this.last; + } + + nextObject = previousObject._iNext; + + // always true in this case + // need to make sure the parents last is updated too + var updateLast = this; + var prevLast = previousObject; + + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + +} + +/** + * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown + * + * @method addChildAt + * @param child {DisplayObject} The child to add + * @param index {Number} The index to place the child in + */ +PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) +{ + if(index >= 0 && index <= this.children.length) + { + if(child.parent != undefined) + { + child.parent.removeChild(child); + } + child.parent = this; + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + var nextObject; + var previousObject; + + if(index == this.children.length) + { + previousObject = this.last; + var updateLast = this; + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + } + else if(index == 0) + { + previousObject = this; + } + else + { + previousObject = this.children[index-1].last; + } + + nextObject = previousObject._iNext; + + // always true in this case + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + this.children.splice(index, 0, child); + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + + } + else + { + throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); + } +} + +/** + * [NYI] Swaps the depth of 2 displayObjects + * + * @method swapChildren + * @param child {DisplayObject} + * @param child2 {DisplayObject} + * @private + */ +PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) +{ + /* + * this funtion needs to be recoded.. + * can be done a lot faster.. + */ + return; + + // need to fix this function :/ + /* + // TODO I already know this?? + var index = this.children.indexOf( child ); + var index2 = this.children.indexOf( child2 ); + + if ( index !== -1 && index2 !== -1 ) + { + // cool + + /* + if(this.stage) + { + // this is to satisfy the webGL batching.. + // TODO sure there is a nicer way to achieve this! + this.stage.__removeChild(child); + this.stage.__removeChild(child2); + + this.stage.__addChild(child); + this.stage.__addChild(child2); + } + + // swap the positions.. + this.children[index] = child2; + this.children[index2] = child; + + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + }*/ +} + +/** + * Returns the Child at the specified index + * + * @method getChildAt + * @param index {Number} The index to get the child from + */ +PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) +{ + if(index >= 0 && index < this.children.length) + { + return this.children[index]; + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + } +} + +/** + * Removes a child from the container. + * + * @method removeChild + * @param child {DisplayObject} The DisplayObject to remove + */ +PIXI.DisplayObjectContainer.prototype.removeChild = function(child) +{ + var index = this.children.indexOf( child ); + if ( index !== -1 ) + { + // unlink // + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + + var nextObject = childLast._iNext; + var previousObject = childFirst._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + if(this.last == childLast) + { + var tempLast = childFirst._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == childLast.last) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + } + + childLast._iNext = null; + childFirst._iPrev = null; + + // update the stage reference.. + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = null; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // webGL trim + if(child.__renderGroup) + { + child.__renderGroup.removeDisplayObjectAndChildren(child); + } + + child.parent = undefined; + this.children.splice( index, 1 ); + } + else + { + throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); + } +} + +/* + * Updates the container's children's transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObjectContainer.prototype.updateTransform = function() +{ + if(!this.visible)return; + + PIXI.DisplayObject.prototype.updateTransform.call( this ); + + for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation + */ +PIXI.MovieClip = function(textures) +{ + PIXI.Sprite.call(this, textures[0]); + + /** + * The array of textures that make up the animation + * + * @property textures + * @type Array + */ + this.textures = textures; + + /** + * The speed that the MovieClip will play at. Higher is faster, lower is slower + * + * @property animationSpeed + * @type Number + * @default 1 + */ + this.animationSpeed = 1; + + /** + * Whether or not the movie clip repeats after playing. + * + * @property loop + * @type Boolean + * @default true + */ + this.loop = true; + + /** + * Function to call when a MovieClip finishes playing + * + * @property onComplete + * @type Function + */ + this.onComplete = null; + + /** + * [read-only] The index MovieClips current frame (this may not have to be a whole number) + * + * @property currentFrame + * @type Number + * @default 0 + * @readOnly + */ + this.currentFrame = 0; + + /** + * [read-only] Indicates if the MovieClip is currently playing + * + * @property playing + * @type Boolean + * @readOnly + */ + this.playing = false; +} + +// constructor +PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); +PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; + +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + +/** + * Stops the MovieClip + * + * @method stop + */ +PIXI.MovieClip.prototype.stop = function() +{ + this.playing = false; +} + +/** + * Plays the MovieClip + * + * @method play + */ +PIXI.MovieClip.prototype.play = function() +{ + this.playing = true; +} + +/** + * Stops the MovieClip and goes to a specific frame + * + * @method gotoAndStop + * @param frameNumber {Number} frame index to stop at + */ +PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) +{ + this.playing = false; + this.currentFrame = frameNumber; + var round = (this.currentFrame + 0.5) | 0; + this.setTexture(this.textures[round % this.textures.length]); +} + +/** + * Goes to a specific frame and begins playing the MovieClip + * + * @method gotoAndPlay + * @param frameNumber {Number} frame index to start at + */ +PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) +{ + this.currentFrame = frameNumber; + this.playing = true; +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.MovieClip.prototype.updateTransform = function() +{ + PIXI.Sprite.prototype.updateTransform.call(this); + + if(!this.playing)return; + + this.currentFrame += this.animationSpeed; + + var round = (this.currentFrame + 0.5) | 0; + + if(this.loop || round < this.textures.length) + { + this.setTexture(this.textures[round % this.textures.length]); + } + else if(round >= this.textures.length) + { + this.gotoAndStop(this.textures.length - 1); + if(this.onComplete) + { + this.onComplete(); + } + } +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + + +PIXI.FilterBlock = function() +{ + this.visible = true; + this.renderable = true; +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text to split a line you can use "\n" + * + * @class Text + * @extends Sprite + * @constructor + * @param text {String} The copy that you would like the text to display + * @param [style] {Object} The style parameters + * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text = function(text, style) +{ + this.canvas = document.createElement("canvas"); + this.context = this.canvas.getContext("2d"); + PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); + + this.setText(text); + this.setStyle(style); + + this.updateText(); + this.dirty = false; +}; + +// constructor +PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); +PIXI.Text.prototype.constructor = PIXI.Text; + +/** + * Set the style of the text + * + * @method setStyle + * @param [style] {Object} The style parameters + * @param [style.font="bold 20pt Arial"] {String} The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text.prototype.setStyle = function(style) +{ + style = style || {}; + style.font = style.font || "bold 20pt Arial"; + style.fill = style.fill || "black"; + style.align = style.align || "left"; + style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 + style.strokeThickness = style.strokeThickness || 0; + style.wordWrap = style.wordWrap || false; + style.wordWrapWidth = style.wordWrapWidth || 100; + this.style = style; + this.dirty = true; +}; + +/** + * Set the copy for the text object. To split a line you can use "\n" + * + * @methos setText + * @param {String} text The copy that you would like the text to display + */ +PIXI.Text.prototype.setText = function(text) +{ + this.text = text.toString() || " "; + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.Text.prototype.updateText = function() +{ + this.context.font = this.style.font; + + var outputText = this.text; + + // word wrap + // preserve original text + if(this.style.wordWrap)outputText = this.wordWrap(this.text); + + //split text into lines + var lines = outputText.split(/(?:\r\n|\r|\n)/); + + //calculate text width + var lineWidths = []; + var maxLineWidth = 0; + for (var i = 0; i < lines.length; i++) + { + var lineWidth = this.context.measureText(lines[i]).width; + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + this.canvas.width = maxLineWidth + this.style.strokeThickness; + + //calculate text height + var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; + this.canvas.height = lineHeight * lines.length; + + //set canvas text styles + this.context.fillStyle = this.style.fill; + this.context.font = this.style.font; + + this.context.strokeStyle = this.style.stroke; + this.context.lineWidth = this.style.strokeThickness; + + this.context.textBaseline = "top"; + + //draw lines line by line + for (i = 0; i < lines.length; i++) + { + var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); + + if(this.style.align == "right") + { + linePosition.x += maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + linePosition.x += (maxLineWidth - lineWidths[i]) / 2; + } + + if(this.style.stroke && this.style.strokeThickness) + { + this.context.strokeText(lines[i], linePosition.x, linePosition.y); + } + + if(this.style.fill) + { + this.context.fillText(lines[i], linePosition.x, linePosition.y); + } + } + + this.updateTexture(); +}; + +/** + * Updates texture size based on canvas size + * + * @method updateTexture + * @private + */ +PIXI.Text.prototype.updateTexture = function() +{ + this.texture.baseTexture.width = this.canvas.width; + this.texture.baseTexture.height = this.canvas.height; + this.texture.frame.width = this.canvas.width; + this.texture.frame.height = this.canvas.height; + + this._width = this.canvas.width; + this._height = this.canvas.height; + + PIXI.texturesToUpdate.push(this.texture.baseTexture); +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.Text.prototype.updateTransform = function() +{ + if(this.dirty) + { + this.updateText(); + this.dirty = false; + } + + PIXI.Sprite.prototype.updateTransform.call(this); +}; + +/* + * http://stackoverflow.com/users/34441/ellisbben + * great solution to the problem! + * + * @method determineFontHeight + * @param fontStyle {Object} + * @private + */ +PIXI.Text.prototype.determineFontHeight = function(fontStyle) +{ + // build a little reference dictionary so if the font style has been used return a + // cached version... + var result = PIXI.Text.heightCache[fontStyle]; + + if(!result) + { + var body = document.getElementsByTagName("body")[0]; + var dummy = document.createElement("div"); + var dummyText = document.createTextNode("M"); + dummy.appendChild(dummyText); + dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); + body.appendChild(dummy); + + result = dummy.offsetHeight; + PIXI.Text.heightCache[fontStyle] = result; + + body.removeChild(dummy); + } + + return result; +}; + +/** + * Applies newlines to a string to have it optimally fit into the horizontal + * bounds set by the Text object's wordWrapWidth property. + * + * @method wordWrap + * @param text {String} + * @private + */ +PIXI.Text.prototype.wordWrap = function(text) +{ + // Greedy wrapping algorithm that will wrap words as the line grows longer + // than its horizontal bounds. + var result = ""; + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) + { + var spaceLeft = this.style.wordWrapWidth; + var words = lines[i].split(" "); + for (var j = 0; j < words.length; j++) + { + var wordWidth = this.context.measureText(words[j]).width; + var wordWidthWithSpace = wordWidth + this.context.measureText(" ").width; + if(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 = this.style.wordWrapWidth - wordWidth; + } + else + { + spaceLeft -= wordWidthWithSpace; + result += words[j] + " "; + } + } + result += "\n"; + } + return result; +}; + +/** + * Destroys this text object + * + * @method destroy + * @param destroyTexture {Boolean} + */ +PIXI.Text.prototype.destroy = function(destroyTexture) +{ + if(destroyTexture) + { + this.texture.destroy(); + } + +}; + +PIXI.Text.heightCache = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" + * You can generate the fnt files using + * http://www.angelcode.com/products/bmfont/ for windows or + * http://www.bmglyph.com/ for mac. + * + * @class BitmapText + * @extends DisplayObjectContainer + * @constructor + * @param text {String} The copy that you would like the text to display + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText = function(text, style) +{ + PIXI.DisplayObjectContainer.call(this); + + this.setText(text); + this.setStyle(style); + this.updateText(); + this.dirty = false + +}; + +// constructor +PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; + +/** + * Set the copy for the text object + * + * @method setText + * @param text {String} The copy that you would like the text to display + */ +PIXI.BitmapText.prototype.setText = function(text) +{ + this.text = text || " "; + this.dirty = true; +}; + +/** + * Set the style of the text + * + * @method setStyle + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText.prototype.setStyle = function(style) +{ + style = style || {}; + style.align = style.align || "left"; + this.style = style; + + var font = style.font.split(" "); + this.fontName = font[font.length - 1]; + this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; + + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.BitmapText.prototype.updateText = function() +{ + var data = PIXI.BitmapText.fonts[this.fontName]; + var pos = new PIXI.Point(); + var prevCharCode = null; + var chars = []; + var maxLineWidth = 0; + var lineWidths = []; + var line = 0; + var scale = this.fontSize / data.size; + for(var i = 0; i < this.text.length; i++) + { + var charCode = this.text.charCodeAt(i); + if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) + { + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + line++; + + pos.x = 0; + pos.y += data.lineHeight; + prevCharCode = null; + continue; + } + + var charData = data.chars[charCode]; + if(!charData) continue; + + if(prevCharCode && charData[prevCharCode]) + { + pos.x += charData.kerning[prevCharCode]; + } + chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); + pos.x += charData.xAdvance; + + prevCharCode = charCode; + } + + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + + var lineAlignOffsets = []; + for(i = 0; i <= line; i++) + { + var alignOffset = 0; + if(this.style.align == "right") + { + alignOffset = maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + alignOffset = (maxLineWidth - lineWidths[i]) / 2; + } + lineAlignOffsets.push(alignOffset); + } + + for(i = 0; i < chars.length; i++) + { + var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); + c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; + c.position.y = chars[i].position.y * scale; + c.scale.x = c.scale.y = scale; + this.addChild(c); + } + + this.width = pos.x * scale; + this.height = (pos.y + data.lineHeight) * scale; +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.BitmapText.prototype.updateTransform = function() +{ + if(this.dirty) + { + while(this.children.length > 0) + { + this.removeChild(this.getChildAt(0)); + } + this.updateText(); + + this.dirty = false; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + +PIXI.BitmapText.fonts = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + /** + * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive + * This manager also supports multitouch. + * + * @class InteractionManager + * @constructor + * @param stage {Stage} The stage to handle interactions + */ +PIXI.InteractionManager = function(stage) +{ + /** + * a refference to the stage + * + * @property stage + * @type Stage + */ + this.stage = stage; + + /** + * the mouse data + * + * @property mouse + * @type InteractionData + */ + this.mouse = new PIXI.InteractionData(); + + /** + * an object that stores current touches (InteractionData) by id reference + * + * @property touchs + * @type Object + */ + this.touchs = {}; + + + + // helpers + this.tempPoint = new PIXI.Point(); + //this.tempMatrix = mat3.create(); + + this.mouseoverEnabled = true; + + //tiny little interactiveData pool! + this.pool = []; + + this.interactiveItems = []; + this.interactionDOMElement = null; + + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + + this.last = 0; +} + +// constructor +PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; + +/** + * Collects an interactive sprite recursively to have their interactions managed + * + * @method collectInteractiveSprite + * @param displayObject {DisplayObject} the displayObject to collect + * @param iParent {DisplayObject} + * @private + */ +PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) +{ + var children = displayObject.children; + var length = children.length; + + /// make an interaction tree... {item.__interactiveParent} + for (var i = length-1; i >= 0; i--) + { + var child = children[i]; + +// if(child.visible) { + // push all interactive bits + if(child.interactive) + { + iParent.interactiveChildren = true; + //child.__iParent = iParent; + this.interactiveItems.push(child); + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, child); + } + } + else + { + child.__iParent = null; + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, iParent); + } + } +// } + } +} + +/** + * Sets the target for event delegation + * + * @method setTarget + * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to + * @private + */ +PIXI.InteractionManager.prototype.setTarget = function(target) +{ + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + + if (window.navigator.msPointerEnabled) + { + // time to remove some of that zoom in ja.. + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; + + // DO some window specific touch! + } + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); +} + + +/** + * updates the state of interactive objects + * + * @method update + * @private + */ +PIXI.InteractionManager.prototype.update = function() +{ + if(!this.target)return; + + // frequency of 30fps?? + var now = Date.now(); + var diff = now - this.last; + diff = (diff * 30) / 1000; + if(diff < 1)return; + this.last = now; + // + + // ok.. so mouse events?? + // yes for now :) + // OPTIMSE - how often to check?? + if(this.dirty) + { + this.dirty = false; + + var len = this.interactiveItems.length; + + for (var i=0; i < len; i++) { + this.interactiveItems[i].interactiveChildren = false; + } + + this.interactiveItems = []; + + if(this.stage.interactive)this.interactiveItems.push(this.stage); + // go through and collect all the objects that are interactive.. + this.collectInteractiveSprite(this.stage, this.stage); + } + + // loop through interactive objects! + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + + //if(!item.visible)continue; + + // OPTIMISATION - only calculate every time if the mousemove function exists.. + // OK so.. does the object have any other interactive functions? + // hit-test the clip! + + + if(item.mouseover || item.mouseout || item.buttonMode) + { + // ok so there are some functions so lets hit test it.. + item.__hit = this.hitTest(item, this.mouse); + this.mouse.target = item; + // ok so deal with interactions.. + // loks like there was a hit! + if(item.__hit) + { + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; + + if(!item.__isOver) + { + + if(item.mouseover)item.mouseover(this.mouse); + item.__isOver = true; + } + } + else + { + if(item.__isOver) + { + // roll out! + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } + } + + // ---> + } +} + +/** + * Is called when the mouse moves accross the renderer element + * + * @method onMouseMove + * @param event {Event} The DOM event of the mouse moving + * @private + */ +PIXI.InteractionManager.prototype.onMouseMove = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + // TODO optimize by not check EVERY TIME! maybe half as often? // + var rect = this.interactionDOMElement.getBoundingClientRect(); + + this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); + this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); + + var length = this.interactiveItems.length; + var global = this.mouse.global; + + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousemove) + { + //call the function! + item.mousemove(this.mouse); + } + } +} + +/** + * Is called when the mouse button is pressed down on the renderer element + * + * @method onMouseDown + * @param event {Event} The DOM event of a mouse button being pressed down + * @private + */ +PIXI.InteractionManager.prototype.onMouseDown = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + // loop through inteaction tree... + // hit test each item! -> + // get interactive items under point?? + //stage.__i + var length = this.interactiveItems.length; + var global = this.mouse.global; + + var index = 0; + var parent = this.stage; + + // while + // hit test + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousedown || item.click) + { + item.__mouseIsDown = true; + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit) + { + //call the function! + if(item.mousedown)item.mousedown(this.mouse); + item.__isDown = true; + + // just the one! + if(!item.interactiveChildren)break; + } + } + } +} + + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + +/** + * Is called when the mouse button is released on the renderer element + * + * @method onMouseUp + * @param event {Event} The DOM event of a mouse button being released + * @private + */ +PIXI.InteractionManager.prototype.onMouseUp = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + var global = this.mouse.global; + + + var length = this.interactiveItems.length; + var up = false; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mouseup || item.mouseupoutside || item.click) + { + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit && !up) + { + //call the function! + if(item.mouseup) + { + item.mouseup(this.mouse); + } + if(item.__isDown) + { + if(item.click)item.click(this.mouse); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.mouseupoutside)item.mouseupoutside(this.mouse); + } + } + + item.__isDown = false; + } + } +} + +/** + * Tests if the current mouse coords hit a sprite + * + * @method hitTest + * @param item {DisplayObject} The displayObject to test for a hit + * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit + * @private + */ +PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) +{ + var global = interactionData.global; + + if(item.vcount !== PIXI.visibleCount)return false; + + var isSprite = (item instanceof PIXI.Sprite), + worldTransform = item.worldTransform, + a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10), + x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; + + interactionData.target = item; + + //a sprite or display object with a hit area defined + if(item.hitArea && item.hitArea.contains) { + if(item.hitArea.contains(x, y)) { + //if(isSprite) + interactionData.target = item; + + return true; + } + + return false; + } + // a sprite with no hitarea defined + else if(isSprite) + { + var width = item.texture.frame.width, + height = item.texture.frame.height, + x1 = -width * item.anchor.x, + y1; + + if(x > x1 && x < x1 + width) + { + y1 = -height * item.anchor.y; + + if(y > y1 && y < y1 + height) + { + // set the target property if a hit is true! + interactionData.target = item + return true; + } + } + } + + var length = item.children.length; + + for (var i = 0; i < length; i++) + { + var tempItem = item.children[i]; + var hit = this.hitTest(tempItem, interactionData); + if(hit) + { + // hmm.. TODO SET CORRECT TARGET? + interactionData.target = item + return true; + } + } + + return false; +} + +/** + * Is called when a touch is moved accross the renderer element + * + * @method onTouchMove + * @param event {Event} The DOM event of a touch moving accross the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchMove = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; + + // update the touch position + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + } + + var length = this.interactiveItems.length; + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + if(item.touchmove)item.touchmove(touchData); + } +} + +/** + * Is called when a touch is started on the renderer element + * + * @method onTouchStart + * @param event {Event} The DOM event of a touch starting on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchStart = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + + var changedTouches = event.changedTouches; + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + + var touchData = this.pool.pop(); + if(!touchData)touchData = new PIXI.InteractionData(); + + touchData.originalEvent = event || window.event; + + this.touchs[touchEvent.identifier] = touchData; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + + if(item.touchstart || item.tap) + { + item.__hit = this.hitTest(item, touchData); + + if(item.__hit) + { + //call the function! + if(item.touchstart)item.touchstart(touchData); + item.__isDown = true; + item.__touchData = touchData; + + if(!item.interactiveChildren)break; + } + } + } + } +} + +/** + * Is called when a touch is ended on the renderer element + * + * @method onTouchEnd + * @param event {Event} The DOM event of a touch ending on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchEnd = function(event) +{ + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + var up = false; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + var itemTouchData = item.__touchData; // <-- Here! + item.__hit = this.hitTest(item, touchData); + + if(itemTouchData == touchData) + { + // so this one WAS down... + touchData.originalEvent = event || window.event; + // hitTest?? + + if(item.touchend || item.tap) + { + if(item.__hit && !up) + { + if(item.touchend)item.touchend(touchData); + if(item.__isDown) + { + if(item.tap)item.tap(touchData); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.touchendoutside)item.touchendoutside(touchData); + } + } + + item.__isDown = false; + } + + item.__touchData = null; + + } + else + { + + } + } + // remove the touch.. + this.pool.push(touchData); + this.touchs[touchEvent.identifier] = null; + } +} + +/** + * Holds all information related to an Interaction event + * + * @class InteractionData + * @constructor + */ +PIXI.InteractionData = function() +{ + /** + * This point stores the global coords of where the touch/mouse event happened + * + * @property global + * @type Point + */ + this.global = new PIXI.Point(); + + // this is here for legacy... but will remove + this.local = new PIXI.Point(); + + /** + * The target Sprite that was interacted with + * + * @property target + * @type Sprite + */ + this.target; + + /** + * When passed to an event handler, this will be the original DOM Event that was captured + * + * @property originalEvent + * @type Event + */ + this.originalEvent; +} + +/** + * This will return the local coords of the specified displayObject for this InteractionData + * + * @method getLocalPosition + * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off + * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject + */ +PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) +{ + var worldTransform = displayObject.worldTransform; + var global = this.global; + + // do a cheeky transform to get the mouse coords; + var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10); + // set the mouse coords... + return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) +} + +// constructor +PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Stage represents the root of the display tree. Everything connected to the stage is rendered + * + * @class Stage + * @extends DisplayObjectContainer + * @constructor + * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format + * like: 0xFFFFFF for white + */ +PIXI.Stage = function(backgroundColor) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create(); + + /** + * Whether or not the stage is interactive + * + * @property interactive + * @type Boolean + */ + this.interactive = true; + + /** + * The interaction manage for this stage, manages all interactive activity on the stage + * + * @property interactive + * @type InteractionManager + */ + this.interactionManager = new PIXI.InteractionManager(this); + + /** + * Whether the stage is dirty and needs to have interactions updated + * + * @property dirty + * @type Boolean + * @private + */ + this.dirty = true; + + this.__childrenAdded = []; + this.__childrenRemoved = []; + + //the stage is it's own stage + this.stage = this; + + //optimize hit detection a bit + this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); + + this.setBackgroundColor(backgroundColor); + this.worldVisible = true; +} + +// constructor +PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Stage.prototype.constructor = PIXI.Stage; + +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Stage.prototype.updateTransform = function() +{ + this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; + + for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + +/** + * A polyfill for Function.prototype.bind + * + * @method bind + */ +if (typeof Function.prototype.bind != 'function') { + Function.prototype.bind = (function () { + var slice = Array.prototype.slice; + return function (thisArg) { + var target = this, boundArgs = slice.call(arguments, 1); + + if (typeof target != 'function') throw new TypeError(); + + function bound() { + var args = boundArgs.concat(slice.call(arguments)); + target.apply(this instanceof bound ? this : thisArg, args); + } + + bound.prototype = (function F(proto) { + proto && (F.prototype = proto); + if (!(this instanceof F)) return new F; + })(target.prototype); + + return bound; + }; + })(); +} + +/** + * A wrapper for ajax requests to be handled cross browser + * + * @class AjaxRequest + * @constructor + */ +var AjaxRequest = PIXI.AjaxRequest = function() +{ + var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE + + if (window.ActiveXObject) + { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) + for (var i=0; i>>>>>>>>") + console.log("_") + var safe = 0; + var tmp = item.first; + console.log(tmp); + + while(tmp._iNext) + { + safe++; + tmp = tmp._iNext; + console.log(tmp); + // console.log(tmp); + + if(safe > 100) + { + console.log("BREAK") + break + } + } +} + + + + + + +/** + * https://github.com/mrdoob/eventtarget.js/ + * THankS mr DOob! + */ + +/** + * Adds event emitter functionality to a class + * + * @class EventTarget + * @example + * function MyEmitter() { + * PIXI.EventTarget.call(this); //mixes in event target stuff + * } + * + * var em = new MyEmitter(); + * em.emit({ type: 'eventName', data: 'some data' }); + */ +PIXI.EventTarget = function () { + + var listeners = {}; + + this.addEventListener = this.on = function ( type, listener ) { + + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + } + + }; + + this.dispatchEvent = this.emit = function ( event ) { + + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + + } + + }; + + this.removeEventListener = this.off = function ( type, listener ) { + + var index = listeners[ type ].indexOf( listener ); + + if ( index !== - 1 ) { + + listeners[ type ].splice( index, 1 ); + + } + + }; + +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * This helper function will automatically detect which renderer you should be using. + * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by + * the browser then this function will return a canvas renderer + * + * @method autoDetectRenderer + * @static + * @param width {Number} the width of the renderers view + * @param height {Number} the height of the renderers view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias + */ +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) +{ + if(!width)width = 800; + if(!height)height = 600; + + // BORROWED from Mr Doob (mrdoob.com) + var webgl = ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(); + + if(webgl) + { + var ie = (navigator.userAgent.toLowerCase().indexOf('msie') != -1); + webgl = !ie; + } + + //console.log(webgl); + if( webgl ) + { + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); + } + + return new PIXI.CanvasRenderer(width, height, view, transparent); +}; + + + +/* + PolyK library + url: http://polyk.ivank.net + Released under MIT licence. + + Copyright (c) 2012 Ivan Kuckir + + 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. + + This is an amazing lib! + + slightly modified by mat groves (matgroves.com); +*/ + +PIXI.PolyK = {}; + +/** + * Triangulates shapes for webGL graphic fills + * + * @method Triangulate + * @namespace PolyK + * @constructor + */ +PIXI.PolyK.Triangulate = function(p) +{ + var sign = true; + + var n = p.length>>1; + if(n<3) return []; + var tgs = []; + var avl = []; + for(var i=0; i 3) + { + var i0 = avl[(i+0)%al]; + var i1 = avl[(i+1)%al]; + var i2 = avl[(i+2)%al]; + + var ax = p[2*i0], ay = p[2*i0+1]; + var bx = p[2*i1], by = p[2*i1+1]; + var cx = p[2*i2], cy = p[2*i2+1]; + + var earFound = false; + if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) + { + earFound = true; + for(var j=0; j 3*al) + { + // need to flip flip reverse it! + // reset! + if(sign) + { + var tgs = []; + avl = []; + for(var i=0; i= 0) && (v >= 0) && (u + v < 1); +} + +/** + * Checks if a shape is convex + * + * @class _convex + * @namespace PolyK + * @private + */ +PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) +{ + return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.initDefaultShaders = function() +{ + PIXI.primitiveShader = new PIXI.PrimitiveShader(); + PIXI.primitiveShader.init(); + + PIXI.stripShader = new PIXI.StripShader(); + PIXI.stripShader.init(); + + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + + var gl = PIXI.gl; + var shaderProgram = PIXI.defaultShader.program; + + + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.activatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.primitiveShader.program); + + gl.disableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + + gl.enableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.primitiveShader.colorAttribute); +} + +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + + gl.disableVertexAttribArray(PIXI.primitiveShader.aVertexPosition); + gl.disableVertexAttribArray(PIXI.primitiveShader.colorAttribute); + + gl.enableVertexAttribArray(PIXI.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(PIXI.defaultShader.colorAttribute); + gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); + +} + +PIXI.activateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.stripShader.program); + // gl.disableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +PIXI.deactivateStripShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.defaultShader.program); + //gl.enableVertexAttribArray(PIXI.defaultShader.aTextureCoord); +} + +/* + +SHADER COMPILER HELPERS +*/ + +PIXI.CompileVertexShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); +} + +PIXI.CompileFragmentShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); +} + +PIXI._CompileShader = function(gl, shaderSrc, shaderType) +{ + var src = shaderSrc.join("\n"); + var shader = gl.createShader(shaderType); + gl.shaderSource(shader, src); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} + + +PIXI.compileProgram = function(vertexSrc, fragmentSrc) +{ + var gl = PIXI.gl; + var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); + var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); + + var shaderProgram = gl.createProgram(); + + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialise shaders"); + } + + return shaderProgram; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * @author Richard Davey http://www.photonstorm.com @photonstorm + */ + +/** +* @class PIXI.PixiShader +* @constructor +*/ +PIXI.PixiShader = function() +{ + /** + * @property {any} program - The WebGL program. + */ + this.program; + + /** + * @property {array} fragmentSrc - The fragment shader. + */ + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + + /** + * @property {number} textureCount - A local texture counter for multi-texture shaders. + */ + this.textureCount = 0; + +} + +/** +* @method PIXI.PixiShader#init +*/ +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +/** +* Updates the shader uniform values. +* Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/ +* http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf +* +* @method PIXI.PixiShader#syncUniforms +*/ +PIXI.PixiShader.prototype.syncUniforms = function() +{ + this.textureCount = 1; + + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + var type = this.uniforms[key].type; + var transpose = false; + + if (this.uniforms[key].transpose) + { + transpose = this.uniforms[key].transpose; + } + + if (type == "1f") + { + // void uniform1f(WebGLUniformLocation? location, GLfloat x); + gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1fv") + { + // void uniform1fv(WebGLUniformLocation? location, Float32Array v); + // void uniform1fv(WebGLUniformLocation? location, sequence v); + gl.uniform1fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1i") + { + // void uniform1i(WebGLUniformLocation? location, GLint x); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "1iv") + { + // void uniform1iv(WebGLUniformLocation? location, Int32Array v); + // void uniform1iv(WebGLUniformLocation? location, sequence v); + gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2f") + { + // void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y); + gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2fv") + { + // void uniform2fv(WebGLUniformLocation? location, Float32Array v); + // void uniform2fv(WebGLUniformLocation? location, sequence v); + gl.uniform2fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "2i") + { + // void uniform2i(WebGLUniformLocation? location, GLint x, GLint y); + gl.uniform2i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); + } + else if (type == "2iv") + { + // void uniform2iv(WebGLUniformLocation? location, Int32Array v); + // void uniform2iv(WebGLUniformLocation? location, sequence v); + gl.uniform2iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3f") + { + // void uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z); + gl.uniform3f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3fv") + { + // void uniform3fv(WebGLUniformLocation? location, Float32Array v); + // void uniform3fv(WebGLUniformLocation? location, sequence v); + gl.uniform3fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "3i") + { + // void uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z); + gl.uniform3i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); + } + else if (type == "3iv") + { + // void uniform3iv(WebGLUniformLocation? location, Int32Array v); + // void uniform3iv(WebGLUniformLocation? location, sequence v); + gl.uniform3iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4f") + { + // void uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + gl.uniform4f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4fv") + { + // void uniform4fv(WebGLUniformLocation? location, Float32Array v); + // void uniform4fv(WebGLUniformLocation? location, sequence v); + gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "4i") + { + // void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w); + gl.uniform4i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); + } + else if (type == "4iv") + { + // void uniform4iv(WebGLUniformLocation? location, Int32Array v); + // void uniform4iv(WebGLUniformLocation? location, sequence v); + gl.uniform4iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); + } + else if (type == "mat2") + { + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix2fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat3") + { + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix3fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "mat4") + { + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); + // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); + gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); + } + else if (type == "sampler2D") + { + if (this.uniforms[key].value.baseTexture.hasLoaded) + { + var texture = this.uniforms[key].value.baseTexture._glTexture; + var image = this.uniforms[key].value.baseTexture.source; + var format = gl.RGBA; + + if (this.uniforms[key].format && this.uniforms[key].format == 'luminance') + { + format = gl.LUMINANCE; + } + + gl.activeTexture(gl['TEXTURE' + this.textureCount]); + + if (this.uniforms[key].wrap) + { + if (this.uniforms[key].wrap == 'no-repeat' || this.uniforms[key].wrap === false) + { + this.createGLTextureLinear(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'repeat' || this.uniforms[key].wrap === true) + { + this.createGLTexture(gl, image, format, texture); + } + else if (this.uniforms[key].wrap == 'nearest-repeat') + { + this.createGLTextureNearestRepeat(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'nearest') + { + this.createGLTextureNearest(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'audio') + { + this.createAudioTexture(gl, texture); + } + else if (this.uniforms[key].wrap == 'keyboard') + { + this.createKeyboardTexture(gl, texture); + } + } + else + { + this.createGLTextureLinear(gl, image, texture); + } + + gl.uniform1i(this.uniforms[key].uniformLocation, this.textureCount); + + this.textureCount++; + } + } + } + +}; + +/** +* Binds the given texture and image data. The texture is set to REPEAT. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTexture +*/ +PIXI.PixiShader.prototype.createGLTexture = function(gl, image, format, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.generateMipmap(gl.TEXTURE_2D); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureLinear +*/ +PIXI.PixiShader.prototype.createGLTextureLinear = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture and image data. The texture is set to REPEAT with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearestRepeat +*/ +PIXI.PixiShader.prototype.createGLTextureNearestRepeat = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); +} + +/** +* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE with NEAREST. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createGLTextureNearest +*/ +PIXI.PixiShader.prototype.createGLTextureNearest = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with real-time audio data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createAudioTexture +*/ +PIXI.PixiShader.prototype.createAudioTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 512, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +/** +* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with keyboard input data. +* Code based on Effects.js from ShaderToy.com +* @method PIXI.PixiShader#createKeyboardTexture +*/ +PIXI.PixiShader.prototype.createKeyboardTexture = function(gl, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 256, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +PIXI.PixiShader.defaultVertexSrc = [ + + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "varying vec2 vTextureCoord;", + + "varying float vColor;", + + "const vec2 center = vec2(-1.0, 1.0);", + + "void main(void) {", + "gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" +]; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.StripShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float alpha;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", + "gl_FragColor = gl_FragColor * alpha;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "varying vec2 vTextureCoord;", + "varying vec2 offsetVector;", + "varying float vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" + ]; +} + +PIXI.StripShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.uSampler = gl.getUniformLocation(program, "uSampler"); + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PrimitiveShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec4 vColor;", + "void main(void) {", + "gl_FragColor = vColor;", + "}" + ]; + + this.vertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec4 aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "uniform vec2 offsetVector;", + "uniform float alpha;", + "varying vec4 vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);", + "v -= offsetVector.xyx;", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vColor = aColor * alpha;", + "}" + ]; + +} + +PIXI.PrimitiveShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc, this.fragmentSrc); + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get and store the uniforms for the shader + this.projectionVector = gl.getUniformLocation(program, "projectionVector"); + this.offsetVector = gl.getUniformLocation(program, "offsetVector"); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); + this.colorAttribute = gl.getAttribLocation(program, "aColor"); + + this.translationMatrix = gl.getUniformLocation(program, "translationMatrix"); + this.alpha = gl.getUniformLocation(program, "alpha"); + + this.program = program; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A set of functions used by the webGL renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.WebGLGraphics = function() +{ + +} + +/** + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param projection {Object} + */ +PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) +{ + var gl = PIXI.gl; + + if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, + buffer:gl.createBuffer(), + indexBuffer:gl.createBuffer()}; + + if(graphics.dirty) + { + graphics.dirty = false; + + if(graphics.clearDirty) + { + graphics.clearDirty = false; + + graphics._webGL.lastIndex = 0; + graphics._webGL.points = []; + graphics._webGL.indices = []; + + } + + PIXI.WebGLGraphics.updateGraphics(graphics); + } + + PIXI.activatePrimitiveShader(); + + // This could be speeded up fo sure! + var m = PIXI.mat3.clone(graphics.worldTransform); + + PIXI.mat3.transpose(m); + + // set the matrix transform for the + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + gl.uniformMatrix3fv(PIXI.primitiveShader.translationMatrix, false, m); + + gl.uniform2f(PIXI.primitiveShader.projectionVector, projection.x, -projection.y); + gl.uniform2f(PIXI.primitiveShader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(PIXI.primitiveShader.alpha, graphics.worldAlpha); + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + + gl.vertexAttribPointer(PIXI.primitiveShader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); + gl.vertexAttribPointer(PIXI.primitiveShader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); + + // set the index buffer! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + + + gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + + PIXI.deactivatePrimitiveShader(); + + + // return to default shader... +// PIXI.activateShader(PIXI.defaultShader); +} + +/** + * Updates the graphics object + * + * @static + * @private + * @method updateGraphics + * @param graphics {Graphics} + */ +PIXI.WebGLGraphics.updateGraphics = function(graphics) +{ + for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + + if(data.type == PIXI.Graphics.POLY) + { + if(data.fill) + { + if(data.points.length>3) + PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); + } + + if(data.lineWidth > 0) + { + PIXI.WebGLGraphics.buildLine(data, graphics._webGL); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); + } + else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) + { + PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); + } + }; + + graphics._webGL.lastIndex = graphics.graphicsData.length; + + var gl = PIXI.gl; + + graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); + + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); + + graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); +} + +/** + * Builds a rectangle to draw + * + * @static + * @private + * @method buildRectangle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vertPos = verts.length/6; + + // start + verts.push(x, y); + verts.push(r, g, b, alpha); + + verts.push(x + width, y); + verts.push(r, g, b, alpha); + + verts.push(x , y + height); + verts.push(r, g, b, alpha); + + verts.push(x + width, y + height); + verts.push(r, g, b, alpha); + + // insert 2 dead triangles.. + indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) + } + + if(graphicsData.lineWidth) + { + graphicsData.points = [x, y, + x + width, y, + x + width, y + height, + x, y + height, + x, y]; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a circle to draw + * + * @static + * @private + * @method buildCircle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + var totalSegs = 40; + var seg = (Math.PI * 2) / totalSegs ; + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vecPos = verts.length/6; + + indices.push(vecPos); + + for (var i=0; i < totalSegs + 1 ; i++) + { + verts.push(x,y, r, g, b, alpha); + + verts.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height, + r, g, b, alpha); + + indices.push(vecPos++, vecPos++); + }; + + indices.push(vecPos-1); + } + + if(graphicsData.lineWidth) + { + graphicsData.points = []; + + for (var i=0; i < totalSegs + 1; i++) + { + graphicsData.points.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height) + }; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a line to draw + * + * @static + * @private + * @method buildLine + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) +{ + // TODO OPTIMISE! + + var wrap = true; + var points = graphicsData.points; + if(points.length == 0)return; + + // if the line width is an odd number add 0.5 to align to a whole pixel + if(graphicsData.lineWidth%2) + { + for (var i = 0; i < points.length; i++) { + points[i] += 0.5; + }; + } + + // get first and last point.. figure out the middle! + var firstPoint = new PIXI.Point( points[0], points[1] ); + var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + // if the first point is the last point - goona have issues :) + if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) + { + points.pop(); + points.pop(); + + lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; + var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; + + points.unshift(midPointX, midPointY); + points.push(midPointX, midPointY) + } + + var verts = webGLData.points; + var indices = webGLData.indices; + var length = points.length / 2; + var indexCount = points.length; + var indexStart = verts.length/6; + + // DRAW the Line + var width = graphicsData.lineWidth / 2; + + // sort color + var color = HEXtoRGB(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var p1x, p1y, p2x, p2y, p3x, p3y; + var perpx, perpy, perp2x, perp2y, perp3x, perp3y; + var ipx, ipy; + var a1, b1, c1, a2, b2, c2; + var denom, pdist, dist; + + p1x = points[0]; + p1y = points[1]; + + p2x = points[2]; + p2y = points[3]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + // start + verts.push(p1x - perpx , p1y - perpy, + r, g, b, alpha); + + verts.push(p1x + perpx , p1y + perpy, + r, g, b, alpha); + + for (var i = 1; i < length-1; i++) + { + p1x = points[(i-1)*2]; + p1y = points[(i-1)*2 + 1]; + + p2x = points[(i)*2] + p2y = points[(i)*2 + 1] + + p3x = points[(i+1)*2]; + p3y = points[(i+1)*2 + 1]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + perp2x = -(p2y - p3y); + perp2y = p2x - p3x; + + dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); + perp2x /= dist; + perp2y /= dist; + perp2x *= width; + perp2y *= width; + + a1 = (-perpy + p1y) - (-perpy + p2y); + b1 = (-perpx + p2x) - (-perpx + p1x); + c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); + a2 = (-perp2y + p3y) - (-perp2y + p2y); + b2 = (-perp2x + p2x) - (-perp2x + p3x); + c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); + + denom = a1*b2 - a2*b1; + + if(Math.abs(denom) < 0.1 ) + { + + denom+=10.1; + verts.push(p2x - perpx , p2y - perpy, + r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy, + r, g, b, alpha); + + continue; + } + + px = (b1*c2 - b2*c1)/denom; + py = (a2*c1 - a1*c2)/denom; + + + pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); + + + if(pdist > 140 * 140) + { + perp3x = perpx - perp2x; + perp3y = perpy - perp2y; + + dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); + perp3x /= dist; + perp3y /= dist; + perp3x *= width; + perp3y *= width; + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x + perp3x, p2y +perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + indexCount++; + } + else + { + + verts.push(px , py); + verts.push(r, g, b, alpha); + + verts.push(p2x - (px-p2x), p2y - (py - p2y)); + verts.push(r, g, b, alpha); + } + } + + p1x = points[(length-2)*2] + p1y = points[(length-2)*2 + 1] + + p2x = points[(length-1)*2] + p2y = points[(length-1)*2 + 1] + + perpx = -(p1y - p2y) + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + verts.push(p2x - perpx , p2y - perpy) + verts.push(r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy) + verts.push(r, g, b, alpha); + + indices.push(indexStart); + + for (var i=0; i < indexCount; i++) + { + indices.push(indexStart++); + }; + + indices.push(indexStart-1); +} + +/** + * Builds a polygon to draw + * + * @static + * @private + * @method buildPoly + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) +{ + var points = graphicsData.points; + if(points.length < 6)return; + + // get first and last point.. figure out the middle! + var verts = webGLData.points; + var indices = webGLData.indices; + + var length = points.length / 2; + + // sort color + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var triangles = PIXI.PolyK.Triangulate(points); + + var vertPos = verts.length / 6; + + for (var i=0; i < triangles.length; i+=3) + { + indices.push(triangles[i] + vertPos); + indices.push(triangles[i] + vertPos); + indices.push(triangles[i+1] + vertPos); + indices.push(triangles[i+2] +vertPos); + indices.push(triangles[i+2] + vertPos); + }; + + for (var i = 0; i < length; i++) + { + verts.push(points[i * 2], points[i * 2 + 1], + r, g, b, alpha); + }; +} + +function HEXtoRGB(hex) { + return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); + +// an instance of the gl context.. +// only one at the moment :/ +PIXI.gl; + +/** + * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer + * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. + * So no need for Sprite Batch's or Sprite Cloud's + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class WebGLRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) + * + */ +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) +{ + // do a catch.. only 1 webGL renderer.. + + this.transparent = !!transparent; + + this.width = width || 800; + this.height = height || 600; + + this.view = view || document.createElement( 'canvas' ); + this.view.width = this.width; + this.view.height = this.height; + + // deal with losing context.. + var scope = this; + this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) + this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) + + this.batchs = []; + + var options = { + alpha: this.transparent, + antialias:!!antialias, // SPEED UP?? + premultipliedAlpha:false, + stencil:true + } + + //try 'experimental-webgl' + try { + PIXI.gl = this.gl = this.view.getContext("experimental-webgl", options); + } catch (e) { + //try 'webgl' + try { + PIXI.gl = this.gl = this.view.getContext("webgl", options); + } catch (e) { + // fail, not able to get a context + throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); + } + } + + PIXI.initDefaultShaders(); + + + + + // PIXI.activateDefaultShader(); + + var gl = this.gl; + + gl.useProgram(PIXI.defaultShader.program); + + + PIXI.WebGLRenderer.gl = gl; + + this.batch = new PIXI.WebGLBatch(gl); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, this.transparent); + + PIXI.projection = new PIXI.Point(400, 300); + PIXI.offset = new PIXI.Point(0, 0); + + // TODO remove thease globals.. + + this.resize(this.width, this.height); + this.contextLost = false; + + //PIXI.pushShader(PIXI.defaultShader); + + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent); + // this.stageRenderGroup. = this.transparent +} + +// constructor +PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; + +/** + * Gets a new WebGLBatch from the pool + * + * @static + * @method getBatch + * @return {WebGLBatch} + * @private + */ +PIXI.WebGLRenderer.getBatch = function() +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * Puts a batch back into the pool + * + * @static + * @method returnBatch + * @param batch {WebGLBatch} The batch to return + * @private + */ +PIXI.WebGLRenderer.returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * Renders the stage to its webGL view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.WebGLRenderer.prototype.render = function(stage) +{ + if(this.contextLost)return; + + + // if rendering a new stage clear the batchs.. + if(this.__stage !== stage) + { + // TODO make this work + // dont think this is needed any more? + this.__stage = stage; + this.stageRenderGroup.setRenderable(stage); + } + + // update any textures + PIXI.WebGLRenderer.updateTextures(); + + // update the scene graph + PIXI.visibleCount++; + stage.updateTransform(); + + var gl = this.gl; + + // -- Does this need to be set every frame? -- // + gl.colorMask(true, true, true, this.transparent); + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + gl.clear(gl.COLOR_BUFFER_BIT); + + // HACK TO TEST + + this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + this.stageRenderGroup.render(PIXI.projection); + + // interaction + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // after rendering lets confirm all frames that have been uodated.. + if(PIXI.Texture.frameUpdates.length > 0) + { + for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) + { + PIXI.Texture.frameUpdates[i].updateFrame = false; + }; + + PIXI.Texture.frameUpdates = []; + } +} + +/** + * Updates the textures loaded into this webgl renderer + * + * @static + * @method updateTextures + * @private + */ +PIXI.WebGLRenderer.updateTextures = function() +{ + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; +} + +/** + * Updates a loaded webgl texture + * + * @static + * @method updateTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.updateTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(!texture._glTexture) + { + texture._glTexture = gl.createTexture(); + } + + if(texture.hasLoaded) + { + gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + + // reguler... + + if(!texture._powerOf2) + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + } +} + +/** + * Destroys a loaded webgl texture + * + * @method destroyTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.destroyTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(texture._glTexture) + { + texture._glTexture = gl.createTexture(); + gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + } +} + +/** + * resizes the webGL view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the webGL view + * @param height {Number} the new height of the webGL view + */ +PIXI.WebGLRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; + + this.gl.viewport(0, 0, this.width, this.height); + + //var projectionMatrix = this.projectionMatrix; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = -this.height/2; + + //PIXI.size.x = this.width/2; + //PIXI.size.y = -this.height/2; + +// projectionMatrix[0] = 2/this.width; +// projectionMatrix[5] = -2/this.height; +// projectionMatrix[12] = -1; +// projectionMatrix[13] = 1; +} + +/** + * Handles a lost webgl context + * + * @method handleContextLost + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextLost = function(event) +{ + event.preventDefault(); + this.contextLost = true; +} + +/** + * Handles a restored webgl context + * + * @method handleContextRestored + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) +{ + this.gl = this.view.getContext("experimental-webgl", { + alpha: true + }); + + this.initShaders(); + + for(var key in PIXI.TextureCache) + { + var texture = PIXI.TextureCache[key].baseTexture; + texture._glTexture = null; + PIXI.WebGLRenderer.updateTexture(texture); + }; + + for (var i=0; i < this.batchs.length; i++) + { + this.batchs[i].restoreLostContext(this.gl)// + this.batchs[i].dirty = true; + }; + + PIXI._restoreBatchs(this.gl); + + this.contextLost = false; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._batchs = []; + +/** + * @private + */ +PIXI._getBatch = function(gl) +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * @private + */ +PIXI._returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * @private + */ +PIXI._restoreBatchs = function(gl) +{ + for (var i=0; i < PIXI._batchs.length; i++) + { + PIXI._batchs[i].restoreLostContext(gl); + }; +} + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. + * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites + * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled + * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @constructor + * @param gl {WebGLContext} an instance of the webGL context + */ +PIXI.WebGLBatch = function(gl) +{ + this.gl = gl; + + this.size = 0; + + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); + this.blendMode = PIXI.blendModes.NORMAL; + this.dynamicSize = 1; +} + +// constructor +PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; + +/** + * Cleans the batch so that is can be returned to an object pool and reused + * + * @method clean + */ +PIXI.WebGLBatch.prototype.clean = function() +{ + this.verticies = []; + this.uvs = []; + this.indices = []; + this.colors = []; + this.dynamicSize = 1; + this.texture = null; + this.last = null; + this.size = 0; + this.head; + this.tail; +} + +/** + * Recreates the buffers in the event of a context loss + * + * @method restoreLostContext + * @param gl {WebGLContext} + */ +PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) +{ + this.gl = gl; + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); +} + +/** + * inits the batch's texture and blend mode based if the supplied sprite + * + * @method init + * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with + * the same base texture and blend mode will be allowed to be added to this batch + */ +PIXI.WebGLBatch.prototype.init = function(sprite) +{ + sprite.batch = this; + this.dirty = true; + this.blendMode = sprite.blendMode; + this.texture = sprite.texture.baseTexture; + this.head = sprite; + this.tail = sprite; + this.size = 1; + + this.growBatch(); +} + +/** + * inserts a sprite before the specified sprite + * + * @method insertBefore + * @param sprite {Sprite} the sprite to be added + * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite + */ +PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + var tempPrev = nextSprite.__prev; + nextSprite.__prev = sprite; + sprite.__next = nextSprite; + + if(tempPrev) + { + sprite.__prev = tempPrev; + tempPrev.__next = sprite; + } + else + { + this.head = sprite; + } +} + +/** + * inserts a sprite after the specified sprite + * + * @method insertAfter + * @param sprite {Sprite} the sprite to be added + * @param previousSprite {Sprite} the first sprite will be inserted after this sprite + */ +PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + + var tempNext = previousSprite.__next; + previousSprite.__next = sprite; + sprite.__prev = previousSprite; + + if(tempNext) + { + sprite.__next = tempNext; + tempNext.__prev = sprite; + } + else + { + this.tail = sprite + } +} + +/** + * removes a sprite from the batch + * + * @method remove + * @param sprite {Sprite} the sprite to be removed + */ +PIXI.WebGLBatch.prototype.remove = function(sprite) +{ + this.size--; + + if(this.size == 0) + { + sprite.batch = null; + sprite.__prev = null; + sprite.__next = null; + return; + } + + if(sprite.__prev) + { + sprite.__prev.__next = sprite.__next; + } + else + { + this.head = sprite.__next; + this.head.__prev = null; + } + + if(sprite.__next) + { + sprite.__next.__prev = sprite.__prev; + } + else + { + this.tail = sprite.__prev; + this.tail.__next = null + } + + sprite.batch = null; + sprite.__next = null; + sprite.__prev = null; + this.dirty = true; +} + +/** + * Splits the batch into two with the specified sprite being the start of the new batch. + * + * @method split + * @param sprite {Sprite} the sprite that indicates where the batch should be split + * @return {WebGLBatch} the new batch + */ +PIXI.WebGLBatch.prototype.split = function(sprite) +{ + this.dirty = true; + + var batch = new PIXI.WebGLBatch(this.gl); + batch.init(sprite); + batch.texture = this.texture; + batch.tail = this.tail; + + this.tail = sprite.__prev; + this.tail.__next = null; + + sprite.__prev = null; + // return a splite batch! + + // TODO this size is wrong! + // need to recalculate :/ problem with a linked list! + // unless it gets calculated in the "clean"? + + // need to loop through items as there is no way to know the length on a linked list :/ + var tempSize = 0; + while(sprite) + { + tempSize++; + sprite.batch = batch; + sprite = sprite.__next; + } + + batch.size = tempSize; + this.size -= tempSize; + + return batch; +} + +/** + * Merges two batchs together + * + * @method merge + * @param batch {WebGLBatch} the batch that will be merged + */ +PIXI.WebGLBatch.prototype.merge = function(batch) +{ + this.dirty = true; + + this.tail.__next = batch.head; + batch.head.__prev = this.tail; + + this.size += batch.size; + + this.tail = batch.tail; + + var sprite = batch.head; + while(sprite) + { + sprite.batch = this; + sprite = sprite.__next; + } +} + +/** + * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this + * function is used to increase the size of the batch. It also creates a little extra room so + * that the batch does not need to be resized every time a sprite is added + * + * @method growBatch + */ +PIXI.WebGLBatch.prototype.growBatch = function() +{ + var gl = this.gl; + if( this.size == 1) + { + this.dynamicSize = 1; + } + else + { + this.dynamicSize = this.size * 1.5 + } + // grow verts + this.verticies = new Float32Array(this.dynamicSize * 8); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); + + this.uvs = new Float32Array( this.dynamicSize * 8 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); + + this.dirtyUVS = true; + + this.colors = new Float32Array( this.dynamicSize * 4 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); + + this.dirtyColors = true; + + this.indices = new Uint16Array(this.dynamicSize * 6); + var length = this.indices.length/6; + + for (var i=0; i < length; i++) + { + var index2 = i * 6; + var index3 = i * 4; + this.indices[index2 + 0] = index3 + 0; + this.indices[index2 + 1] = index3 + 1; + this.indices[index2 + 2] = index3 + 2; + this.indices[index2 + 3] = index3 + 0; + this.indices[index2 + 4] = index3 + 2; + this.indices[index2 + 5] = index3 + 3; + }; + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); +} + +/** + * Refresh's all the data in the batch and sync's it with the webGL buffers + * + * @method refresh + */ +PIXI.WebGLBatch.prototype.refresh = function() +{ + var gl = this.gl; + + if (this.dynamicSize < this.size) + { + this.growBatch(); + } + + var indexRun = 0; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; + var a, b, c, d, tx, ty; + + var displayObject = this.head; + + while(displayObject) + { + index = indexRun * 8; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + + colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + + displayObject = displayObject.__next; + + indexRun ++; + } + + this.dirtyUVS = true; + this.dirtyColors = true; +} + +/** + * Updates all the relevant geometry and uploads the data to the GPU + * + * @method update + */ +PIXI.WebGLBatch.prototype.update = function() +{ + var gl = this.gl; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 + + var a, b, c, d, tx, ty; + + var indexRun = 0; + + var displayObject = this.head; + var verticies = this.verticies; + var uvs = this.uvs; + var colors = this.colors; + + while(displayObject) + { + if(displayObject.vcount === PIXI.visibleCount) + { + width = displayObject.texture.frame.width; + height = displayObject.texture.frame.height; + + // TODO trim?? + aX = displayObject.anchor.x;// - displayObject.texture.trim.x + aY = displayObject.anchor.y; //- displayObject.texture.trim.y + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + index = indexRun * 8; + + worldTransform = displayObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + verticies[index + 0 ] = a * w1 + c * h1 + tx; + verticies[index + 1 ] = d * h1 + b * w1 + ty; + + verticies[index + 2 ] = a * w0 + c * h1 + tx; + verticies[index + 3 ] = d * h1 + b * w0 + ty; + + verticies[index + 4 ] = a * w0 + c * h0 + tx; + verticies[index + 5 ] = d * h0 + b * w0 + ty; + + verticies[index + 6] = a * w1 + c * h0 + tx; + verticies[index + 7] = d * h0 + b * w1 + ty; + + if(displayObject.updateFrame || displayObject.texture.updateFrame) + { + this.dirtyUVS = true; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + uvs[index + 0] = frame.x / tw; + uvs[index +1] = frame.y / th; + + uvs[index +2] = (frame.x + frame.width) / tw; + uvs[index +3] = frame.y / th; + + uvs[index +4] = (frame.x + frame.width) / tw; + uvs[index +5] = (frame.y + frame.height) / th; + + uvs[index +6] = frame.x / tw; + uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + } + + // TODO this probably could do with some optimisation.... + if(displayObject.cacheAlpha != displayObject.worldAlpha) + { + displayObject.cacheAlpha = displayObject.worldAlpha; + + var colorIndex = indexRun * 4; + colors[colorIndex] = colors[colorIndex + 1] = colors[colorIndex + 2] = colors[colorIndex + 3] = displayObject.worldAlpha; + this.dirtyColors = true; + } + } + else + { + index = indexRun * 8; + + verticies[index + 0 ] = verticies[index + 1 ] = verticies[index + 2 ] = verticies[index + 3 ] = verticies[index + 4 ] = verticies[index + 5 ] = verticies[index + 6] = verticies[index + 7] = 0; + } + + indexRun++; + displayObject = displayObject.__next; + } +} + +/** + * Draws the batch to the frame buffer + * + * @method render + */ +PIXI.WebGLBatch.prototype.render = function(start, end) +{ + start = start || 0; + + if(end == undefined)end = this.size; + + if(this.dirty) + { + this.refresh(); + this.dirty = false; + } + + if (this.size == 0)return; + + this.update(); + var gl = this.gl; + + //TODO optimize this! + + var shaderProgram = PIXI.defaultShader; + + //gl.useProgram(shaderProgram); + + // update the verts.. + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + // ok.. + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) + gl.vertexAttribPointer(shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + // update the uvs + //var isDefault = (shaderProgram == PIXI.shaderProgram) + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + if(this.dirtyUVS) + { + this.dirtyUVS = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); + } + + gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); + + // update color! + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + + if(this.dirtyColors) + { + this.dirtyColors = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); + } + + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + var len = end - start; + + // DRAW THAT this! + gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be + * grouped into a batch. All the sprites in a batch can then be drawn in one go by the + * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch + * even if the batch only contains one sprite. Batching is handled automatically by the + * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @contructor + * @param gl {WebGLContext} An instance of the webGL context + */ +PIXI.WebGLRenderGroup = function(gl, transparent) +{ + this.gl = gl; + this.root; + + this.backgroundColor; + this.transparent = transparent == undefined ? true : transparent; + + this.batchs = []; + this.toRemove = []; + console.log(this.transparent) + this.filterManager = new PIXI.WebGLFilterManager(this.transparent); +} + +// constructor +PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; + +/** + * Add a display object to the webgl renderer + * + * @method setRenderable + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) +{ + // has this changed?? + if(this.root)this.removeDisplayObjectAndChildren(this.root); + + displayObject.worldVisible = displayObject.visible; + + // soooooo // + // to check if any batchs exist already?? + + // TODO what if its already has an object? should remove it + this.root = displayObject; + this.addDisplayObjectAndChildren(displayObject); +} + +/** + * Renders the stage to its webgl view + * + * @method render + * @param projection {Object} + */ +PIXI.WebGLRenderGroup.prototype.render = function(projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + + var gl = this.gl; + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + // will render all the elements in the group + var renderable; + + for (var i=0; i < this.batchs.length; i++) + { + + renderable = this.batchs[i]; + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + continue; + } + + // render special + this.renderSpecial(renderable, projection); + } + +} + +/** + * Renders a specific displayObject + * + * @method renderSpecific + * @param displayObject {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection, buffer) +{ + PIXI.WebGLRenderer.updateTextures(); + var gl = this.gl; + + gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y); + + this.filterManager.begin(projection, buffer); + + // to do! + // render part of the scene... + + var startIndex; + var startBatchIndex; + + var endIndex; + var endBatchIndex; + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.first; + while(nextRenderable._iNext) + { + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + nextRenderable = nextRenderable._iNext; + } + var startBatch = nextRenderable.batch; + //console.log(nextRenderable); + + //console.log(renderable) + if(nextRenderable instanceof PIXI.Sprite) + { + startBatch = nextRenderable.batch; + + var head = startBatch.head; + var next = head; + + // ok now we have the batch.. need to find the start index! + if(head == nextRenderable) + { + startIndex = 0; + } + else + { + startIndex = 1; + + while(head.__next != nextRenderable) + { + startIndex++; + head = head.__next; + } + } + } + else + { + startBatch = nextRenderable; + } + + // Get the LAST renderable object + var lastRenderable = displayObject.last; + while(lastRenderable._iPrev) + { + if(lastRenderable.renderable && lastRenderable.__renderGroup)break; + lastRenderable = lastRenderable._iNext; + } + + if(lastRenderable instanceof PIXI.Sprite) + { + endBatch = lastRenderable.batch; + + var head = endBatch.head; + + if(head == lastRenderable) + { + endIndex = 0; + } + else + { + endIndex = 1; + + while(head.__next != lastRenderable) + { + endIndex++; + head = head.__next; + } + } + } + else + { + endBatch = lastRenderable; + } + + //console.log(endBatch); + // TODO - need to fold this up a bit! + + if(startBatch == endBatch) + { + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex, endIndex+1); + } + else + { + this.renderSpecial(startBatch, projection); + } + return; + } + + // now we have first and last! + startBatchIndex = this.batchs.indexOf(startBatch); + endBatchIndex = this.batchs.indexOf(endBatch); + + // DO the first batch + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex); + } + else + { + this.renderSpecial(startBatch, projection); + } + + // DO the middle batchs.. + for (var i=startBatchIndex+1; i < endBatchIndex; i++) + { + renderable = this.batchs[i]; + + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + } + else + { + this.renderSpecial(renderable, projection); + } + } + + // DO the last batch.. + if(endBatch instanceof PIXI.WebGLBatch) + { + endBatch.render(0, endIndex+1); + } + else + { + this.renderSpecial(endBatch, projection); + } +} + +/** + * Renders a specific renderable + * + * @method renderSpecial + * @param renderable {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) +{ + + var worldVisible = renderable.vcount === PIXI.visibleCount + + + if(renderable instanceof PIXI.TilingSprite) + { + if(worldVisible)this.renderTilingSprite(renderable, projection); + } + else if(renderable instanceof PIXI.Strip) + { + if(worldVisible)this.renderStrip(renderable, projection); + } + else if(renderable instanceof PIXI.CustomRenderable) + { + if(worldVisible) renderable.renderWebGL(this, projection); + } + else if(renderable instanceof PIXI.Graphics) + { + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + } + else if(renderable instanceof PIXI.FilterBlock) + { + this.handleFilterBlock(renderable, projection); + } +} + +flip = false; +var maskStack = []; +var maskPosition = 0; + +//var usedMaskStack = []; + +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(filterBlock, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; + + if(filterBlock.open) + { + if(filterBlock.data instanceof Array) + { + this.filterManager.pushFilter(filterBlock); + // ok so.. + + } + else + { + maskPosition++; + + maskStack.push(filterBlock) + + gl.enable(gl.STENCIL_TEST); + + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); + + PIXI.WebGLGraphics.renderGraphics(filterBlock.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + } + } + else + { + if(filterBlock.data instanceof Array) + { + this.filterManager.popFilter(); + } + else + { + var maskData = maskStack.pop(filterBlock) + + + if(maskData) + { + gl.colorMask(false, false, false, false); + + gl.stencilFunc(gl.ALWAYS,1,1); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); + + PIXI.WebGLGraphics.renderGraphics(maskData.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + }; + + gl.disable(gl.STENCIL_TEST); + } + } +} + +/** + * Updates a webgl texture + * + * @method updateTexture + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) +{ + + // TODO definitely can optimse this function.. + + this.removeObject(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = displayObject.first; + while(previousRenderable != this.root) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + this.insertObject(displayObject, previousRenderable, nextRenderable); +} + +/** + * Adds filter blocks + * + * @method addFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) +{ + start.__renderGroup = this; + end.__renderGroup = this; + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = start; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + this.insertAfter(start, previousRenderable); + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var previousRenderable2 = end; + while(previousRenderable2 != this.root.first) + { + previousRenderable2 = previousRenderable2._iPrev; + if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; + } + this.insertAfter(end, previousRenderable2); +} + +/** + * Remove filter blocks + * + * @method removeFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) +{ + this.removeObject(start); + this.removeObject(end); +} + +/** + * Adds a display object and children to the webgl context + * + * @method addDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + + var previousRenderable = displayObject.first; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + // one the display object hits this. we can break the loop + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + do + { + tempObject.__renderGroup = this; + + if(tempObject.renderable) + { + + this.insertObject(tempObject, previousRenderable, nextRenderable); + previousRenderable = tempObject; + } + + tempObject = tempObject._iNext; + } + while(tempObject != testObject) +} + +/** + * Removes a display object and children to the webgl context + * + * @method removeDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup != this)return; + +// var displayObject = displayObject.first; + var lastObject = displayObject.last; + do + { + displayObject.__renderGroup = null; + if(displayObject.renderable)this.removeObject(displayObject); + displayObject = displayObject._iNext; + } + while(displayObject) +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertObject + * @param displayObject {DisplayObject} + * @param previousObject {DisplayObject} + * @param nextObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) +{ + // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED + var previousSprite = previousObject; + var nextSprite = nextObject; + + /* + * so now we have the next renderable and the previous renderable + * + */ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch + var nextBatch + + if(previousSprite instanceof PIXI.Sprite) + { + previousBatch = previousSprite.batch; + if(previousBatch) + { + if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) + { + previousBatch.insertAfter(displayObject, previousSprite); + return; + } + } + } + else + { + // TODO reword! + previousBatch = previousSprite; + } + + if(nextSprite) + { + if(nextSprite instanceof PIXI.Sprite) + { + nextBatch = nextSprite.batch; + + //batch may not exist if item was added to the display list but not to the webGL + if(nextBatch) + { + if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) + { + nextBatch.insertBefore(displayObject, nextSprite); + return; + } + else + { + if(nextBatch == previousBatch) + { + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(nextSprite); + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var batch = PIXI.WebGLRenderer.getBatch(); + + var index = this.batchs.indexOf( previousBatch ); + batch.init(displayObject); + this.batchs.splice(index+1, 0, batch, splitBatch); + + return; + } + } + } + } + else + { + // TODO re-word! + + nextBatch = nextSprite; + } + } + + /* + * looks like it does not belong to any batch! + * but is also not intersecting one.. + * time to create anew one! + */ + + var batch = PIXI.WebGLRenderer.getBatch(); + batch.init(displayObject); + + if(previousBatch) // if this is invalid it means + { + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, batch); + } + else + { + this.batchs.push(batch); + } + + return; + } + else if(displayObject instanceof PIXI.TilingSprite) + { + + // add to a batch!! + this.initTilingSprite(displayObject); + // this.batchs.push(displayObject); + + } + else if(displayObject instanceof PIXI.Strip) + { + // add to a batch!! + this.initStrip(displayObject); + // this.batchs.push(displayObject); + } + else if(displayObject)// instanceof PIXI.Graphics) + { + //displayObject.initWebGL(this); + + // add to a batch!! + //this.initStrip(displayObject); + //this.batchs.push(displayObject); + } + + this.insertAfter(displayObject, previousSprite); + + // insert and SPLIT! + +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertAfter + * @param item {DisplayObject} + * @param displayObject {DisplayObject} The object to insert + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) +{ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch = displayObject.batch; + + if(previousBatch) + { + // so this object is in a batch! + + // is it not? need to split the batch + if(previousBatch.tail == displayObject) + { + // is it tail? insert in to batchs + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item); + } + else + { + // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // + + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(displayObject.__next); + + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item, splitBatch); + } + } + else + { + this.batchs.push(item); + } + } + else + { + var index = this.batchs.indexOf( displayObject ); + this.batchs.splice(index+1, 0, item); + } +} + +/** + * Removes a displayObject from the linked list + * + * @method removeObject + * @param displayObject {DisplayObject} The object to remove + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) +{ + // loop through children.. + // display object // + + // add a child from the render group.. + // remove it and all its children! + //displayObject.cacheVisible = false;//displayObject.visible; + + /* + * removing is a lot quicker.. + * + */ + var batchToRemove; + + if(displayObject instanceof PIXI.Sprite) + { + // should always have a batch! + var batch = displayObject.batch; + if(!batch)return; // this means the display list has been altered befre rendering + + batch.remove(displayObject); + + if(batch.size==0) + { + batchToRemove = batch; + } + } + else + { + batchToRemove = displayObject; + } + + /* + * Looks like there is somthing that needs removing! + */ + if(batchToRemove) + { + var index = this.batchs.indexOf( batchToRemove ); + if(index == -1)return;// this means it was added then removed before rendered + + // ok so.. check to see if you adjacent batchs should be joined. + // TODO may optimise? + if(index == 0 || index == this.batchs.length-1) + { + // wha - eva! just get of the empty batch! + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + + return; + } + + if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) + { + if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) + { + //console.log("MERGE") + this.batchs[index-1].merge(this.batchs[index+1]); + + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); + this.batchs.splice(index, 2); + return; + } + } + + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + } +} + + +/** + * Initializes a tiling sprite + * + * @method initTilingSprite + * @param sprite {TilingSprite} The tiling sprite to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) +{ + var gl = this.gl; + + // make the texture tilable.. + + sprite.verticies = new Float32Array([0, 0, + sprite.width, 0, + sprite.width, sprite.height, + 0, sprite.height]); + + sprite.uvs = new Float32Array([0, 0, + 1, 0, + 1, 1, + 0, 1]); + + sprite.colors = new Float32Array([1,1,1,1]); + + sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); + + sprite._vertexBuffer = gl.createBuffer(); + sprite._indexBuffer = gl.createBuffer(); + sprite._uvBuffer = gl.createBuffer(); + sprite._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); + +// return ( (x > 0) && ((x & (x - 1)) == 0) ); + + if(sprite.texture.baseTexture._glTexture) + { + gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + sprite.texture.baseTexture._powerOf2 = true; + } + else + { + sprite.texture.baseTexture._powerOf2 = true; + } +} + +/** + * Renders a Strip + * + * @method renderStrip + * @param strip {Strip} The strip to render + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) +{ + var gl = this.gl; + + PIXI.activateStripShader(); + + var shader = PIXI.stripShader; + + var program = shader.program; + + var m = PIXI.mat3.clone(strip.worldTransform); + + PIXI.mat3.transpose(m); + +// console.log(projection) + // set the matrix transform for the + gl.uniformMatrix3fv(shader.translationMatrix, false, m); + gl.uniform2f(shader.projectionVector, projection.x, projection.y); + gl.uniform2f(shader.offsetVector, -PIXI.offset.x, -PIXI.offset.y); + + gl.uniform1f(shader.alpha, strip.worldAlpha); + + /* + if(strip.blendMode == PIXI.blendModes.NORMAL) + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); + } + */ + + //console.log("!!") + if(!strip.dirty) + { + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + } + else + { + strip.dirty = false; + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + // console.log(strip.texture.baseTexture._glTexture) + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) + gl.vertexAttribPointer(shader.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); + + } + + gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); + + PIXI.deactivateStripShader(); + //gl.useProgram(PIXI.currentProgram); +} + +/** + * Renders a TilingSprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tiling sprite to render + * @param projectionMatrix {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) +{ + var gl = this.gl; + + + var shaderProgram = PIXI.shaderProgram; + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + var offsetX = tilePosition.x/sprite.texture.baseTexture.width; + var offsetY = tilePosition.y/sprite.texture.baseTexture.height; + + var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; + var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; + + sprite.uvs[0] = 0 - offsetX; + sprite.uvs[1] = 0 - offsetY; + + sprite.uvs[2] = (1 * scaleX) -offsetX; + sprite.uvs[3] = 0 - offsetY; + + sprite.uvs[4] = (1 *scaleX) - offsetX; + sprite.uvs[5] = (1 *scaleY) - offsetY; + + sprite.uvs[6] = 0 - offsetX; + sprite.uvs[7] = (1 *scaleY) - offsetY; + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) + + this.renderStrip(sprite, projectionMatrix); +} + +/** + * Initializes a strip to be rendered + * + * @method initStrip + * @param strip {Strip} The strip to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) +{ + // build the strip! + var gl = this.gl; + var shaderProgram = this.shaderProgram; + + strip._vertexBuffer = gl.createBuffer(); + strip._indexBuffer = gl.createBuffer(); + strip._uvBuffer = gl.createBuffer(); + strip._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); + + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.WebGLFilterManager = function(transparent) +{ + this.transparent = transparent; + + this.filterStack = []; + this.texturePool = []; + + this.offsetX = 0; + this.offsetY = 0; + + this.initShaderBuffers(); +} + +// API + +PIXI.WebGLFilterManager.prototype.begin = function(projection, buffer) +{ + this.width = projection.x * 2; + this.height = -projection.y * 2; + this.buffer = buffer; +} + +PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) +{ + var gl = PIXI.gl; + + // filter program + // OPTIMISATION - the first filter is free if its a simple color change? + this.filterStack.push(filterBlock); + + var filter = filterBlock.filterPasses[0]; + + + + this.offsetX += filterBlock.target.filterArea.x; + this.offsetY += filterBlock.target.filterArea.y; + + + + + + var texture = this.texturePool.pop(); + if(!texture)texture = new PIXI.FilterTexture(this.width, this.height); + + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + this.getBounds(filterBlock.target); + + // addpadding? + //displayObject.filterArea.x + + var filterArea = filterBlock.target.filterArea; + + var padidng = filter.padding; + filterArea.x -= padidng; + filterArea.y -= padidng; + filterArea.width += padidng * 2; + filterArea.height += padidng * 2; + + // cap filter to screen size.. + if(filterArea.x < 0)filterArea.x = 0; + if(filterArea.width > this.width)filterArea.width = this.width; + if(filterArea.y < 0)filterArea.y = 0; + if(filterArea.height > this.height)filterArea.height = this.height; + + + //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); + + // console.log(filterArea) + // set view port + gl.viewport(0, 0, filterArea.width, filterArea.height); + + PIXI.projection.x = filterArea.width/2; + PIXI.projection.y = -filterArea.height/2; + + PIXI.offset.x = -filterArea.x; + PIXI.offset.y = -filterArea.y; + + //console.log(PIXI.defaultShader.projectionVector) + // update projection + gl.uniform2f(PIXI.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -filterArea.x, -filterArea.y); + //PIXI.primitiveProgram + + gl.colorMask(true, true, true, true); + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + //filter.texture = texture; + filterBlock._glFilterTexture = texture; + + //console.log("PUSH") +} + + +PIXI.WebGLFilterManager.prototype.popFilter = function() +{ + + var gl = PIXI.gl; + + var filterBlock = this.filterStack.pop(); + + + + var filterArea = filterBlock.target.filterArea; + + var texture = filterBlock._glFilterTexture; + + if(filterBlock.filterPasses.length > 1) + { + gl.viewport(0, 0, filterArea.width, filterArea.height); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = 0; + this.vertexArray[1] = filterArea.height; + + this.vertexArray[2] = filterArea.width; + this.vertexArray[3] = filterArea.height; + + this.vertexArray[4] = 0; + this.vertexArray[5] = 0; + + this.vertexArray[6] = filterArea.width; + this.vertexArray[7] = 0; + + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + // nnow set the uvs.. + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + var inputTexture = texture; + var outputTexture = this.texturePool.pop(); + if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.width, this.height); + + // need to clear this FBO as it may have some left over elements from a prvious filter. + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.disable(gl.BLEND); + + for (var i = 0; i < filterBlock.filterPasses.length-1; i++) + { + var filterPass = filterBlock.filterPasses[i]; + + gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); + + // draw texture.. + //filterPass.applyFilterPass(filterArea.width, filterArea.height); + this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); + + // swap the textures.. + var temp = inputTexture; + inputTexture = outputTexture; + outputTexture = temp; + + }; + + gl.enable(gl.BLEND); + + texture = inputTexture; + this.texturePool.push(outputTexture); + } + + var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; + + this.offsetX -= filterArea.x; + this.offsetY -= filterArea.y; + + + var sizeX = this.width; + var sizeY = this.height; + + var offsetX = 0; + var offsetY = 0; + + var buffer = this.buffer; + + // time to render the filters texture to the previous scene + if(this.filterStack.length === 0) + { + gl.colorMask(true, true, true, this.transparent); + } + else + { + var currentFilter = this.filterStack[this.filterStack.length-1]; + var filterArea = currentFilter.target.filterArea; + + sizeX = filterArea.width; + sizeY = filterArea.height; + + offsetX = filterArea.x; + offsetY = filterArea.y; + + buffer = currentFilter._glFilterTexture.frameBuffer; + } + + + + // TODO need toremove thease global elements.. + PIXI.projection.x = sizeX/2; + PIXI.projection.y = -sizeY/2; + + PIXI.offset.x = offsetX; + PIXI.offset.y = offsetY; + + + var filterArea = filterBlock.target.filterArea; + var x = filterArea.x-offsetX; + var y = filterArea.y-offsetY; + + // update the buffers.. + // make sure to flip the y! + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + + this.vertexArray[0] = x; + this.vertexArray[1] = y + filterArea.height; + + this.vertexArray[2] = x + filterArea.width; + this.vertexArray[3] = y + filterArea.height; + + this.vertexArray[4] = x; + this.vertexArray[5] = y; + + this.vertexArray[6] = x + filterArea.width; + this.vertexArray[7] = y; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + this.uvArray[2] = filterArea.width/this.width; + this.uvArray[5] = filterArea.height/this.height; + this.uvArray[6] = filterArea.width/this.width; + this.uvArray[7] = filterArea.height/this.height; + + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); + + gl.viewport(0, 0, sizeX, sizeY); + // bind the buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); + + // set texture + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + + // apply! + //filter.applyFilterPass(sizeX, sizeY); + this.applyFilterPass(filter, filterArea, sizeX, sizeY); + + // now restore the regular shader.. + gl.useProgram(PIXI.defaultShader.program); + gl.uniform2f(PIXI.defaultShader.projectionVector, sizeX/2, -sizeY/2); + gl.uniform2f(PIXI.defaultShader.offsetVector, -offsetX, -offsetY); + + // return the texture to the pool + this.texturePool.push(texture); + filterBlock._glFilterTexture = null; +} + +PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height) +{ + // use program + var gl = PIXI.gl; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader; + } + + var shader = filter.shader; + + // set the shader + gl.useProgram(shader.program); + + gl.uniform2f(shader.projectionVector, width/2, -height/2); + gl.uniform2f(shader.offsetVector, 0,0) + + if(filter.uniforms.dimensions) + { + //console.log(filter.uniforms.dimensions) + filter.uniforms.dimensions.value[0] = this.width;//width; + filter.uniforms.dimensions.value[1] = this.height;//height; + filter.uniforms.dimensions.value[2] = this.vertexArray[0]; + filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; + // console.log(this.vertexArray[5]) + } + + shader.syncUniforms(); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + // draw the filter... + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); +} + +PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() +{ + var gl = PIXI.gl; + + // create some buffers + this.vertexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + // bind and upload the vertexs.. + // keep a refferance to the vertexFloatData.. + this.vertexArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.vertexArray, + gl.STATIC_DRAW); + + + // bind and upload the uv buffer + this.uvArray = new Float32Array([0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.uvArray, + gl.STATIC_DRAW); + + // bind and upload the index + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData( + gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array([0, 1, 2, 1, 3, 2]), + gl.STATIC_DRAW); +} + +PIXI.WebGLFilterManager.prototype.getBounds = function(displayObject) +{ + // time to get the width and height of the object! + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, doTest; + var a, b, c, d, tx, ty, x1, x2, x3, x4, y1, y2, y3, y4; + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + + var maxX = -Infinity; + var maxY = -Infinity; + + var minX = Infinity; + var minY = Infinity; + + do + { + // TODO can be optimized! - what if there is no scale / rotation? + + if(tempObject.visible) + { + if(tempObject instanceof PIXI.Sprite) + { + width = tempObject.texture.frame.width; + height = tempObject.texture.frame.height; + + // TODO trim?? + aX = tempObject.anchor.x; + aY = tempObject.anchor.y; + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + doTest = true; + } + else if(tempObject instanceof PIXI.Graphics) + { + tempObject.updateFilterBounds(); + + var bounds = tempObject.bounds; + + width = bounds.width; + height = bounds.height; + + w0 = bounds.x + w1 = bounds.x + bounds.width; + + h0 = bounds.y + h1 = bounds.y + bounds.height; + + doTest = true; + } + } + + if(doTest) + { + worldTransform = tempObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + x1 = a * w1 + c * h1 + tx; + y1 = d * h1 + b * w1 + ty; + + x2 = a * w0 + c * h1 + tx; + y2 = d * h1 + b * w0 + ty; + + x3 = a * w0 + c * h0 + tx; + y3 = d * h0 + b * w0 + ty; + + x4 = a * w1 + c * h0 + tx; + y4 = d * h0 + b * w1 + ty; + + minX = x1 < minX ? x1 : minX; + minX = x2 < minX ? x2 : minX; + minX = x3 < minX ? x3 : minX; + minX = x4 < minX ? x4 : minX; + + minY = y1 < minY ? y1 : minY; + minY = y2 < minY ? y2 : minY; + minY = y3 < minY ? y3 : minY; + minY = y4 < minY ? y4 : minY; + + maxX = x1 > maxX ? x1 : maxX; + maxX = x2 > maxX ? x2 : maxX; + maxX = x3 > maxX ? x3 : maxX; + maxX = x4 > maxX ? x4 : maxX; + + maxY = y1 > maxY ? y1 : maxY; + maxY = y2 > maxY ? y2 : maxY; + maxY = y3 > maxY ? y3 : maxY; + maxY = y4 > maxY ? y4 : maxY; + } + + doTest = false; + tempObject = tempObject._iNext; + + } + while(tempObject != testObject) + + // maximum bounds is the size of the screen.. + //minX = minX > 0 ? minX : 0; + //minY = minY > 0 ? minY : 0; + + displayObject.filterArea.x = minX; + displayObject.filterArea.y = minY; + +// console.log(maxX+ " : " + minX) + displayObject.filterArea.width = maxX - minX; + displayObject.filterArea.height = maxY - minY; +} + +PIXI.FilterTexture = function(width, height) +{ + var gl = PIXI.gl; + + // next time to create a frame buffer and texture + this.frameBuffer = gl.createFramebuffer(); + this.texture = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); + + this.resize(width, height); +} + +PIXI.FilterTexture.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + var gl = PIXI.gl; + + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class CanvasRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + */ +PIXI.CanvasRenderer = function(width, height, view, transparent) +{ + this.transparent = transparent; + + /** + * The width of the canvas view + * + * @property width + * @type Number + * @default 800 + */ + this.width = width || 800; + + /** + * The height of the canvas view + * + * @property height + * @type Number + * @default 600 + */ + this.height = height || 600; + + /** + * The canvas element that the everything is drawn to + * + * @property view + * @type Canvas + */ + this.view = view || document.createElement( 'canvas' ); + + /** + * The canvas context that the everything is drawn to + * @property context + * @type Canvas 2d Context + */ + this.context = this.view.getContext("2d"); + + this.refresh = true; + // hack to enable some hardware acceleration! + //this.view.style["transform"] = "translatez(0)"; + + this.view.width = this.width; + this.view.height = this.height; + this.count = 0; +} + +// constructor +PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; + +/** + * Renders the stage to its canvas view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.CanvasRenderer.prototype.render = function(stage) +{ + + //stage.__childrenAdded = []; + //stage.__childrenRemoved = []; + + // update textures if need be + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; + + PIXI.visibleCount++; + stage.updateTransform(); + + // update the background color + if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; + + this.context.setTransform(1,0,0,1,0,0); + this.context.clearRect(0, 0, this.width, this.height) + this.renderDisplayObject(stage); + //as + + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // remove frame updates.. + if(PIXI.Texture.frameUpdates.length > 0) + { + PIXI.Texture.frameUpdates = []; + } + + +} + +/** + * resizes the canvas view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the canvas view + * @param height {Number} the new height of the canvas view + */ +PIXI.CanvasRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; +} + +/** + * Renders a display object + * + * @method renderDisplayObject + * @param displayObject {DisplayObject} The displayObject to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +{ + // no loger recurrsive! + var transform; + var context = this.context; + + context.globalCompositeOperation = 'source-over'; + + // one the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + transform = displayObject.worldTransform; + + if(!displayObject.visible) + { + displayObject = displayObject.last._iNext; + continue; + } + + if(!displayObject.renderable) + { + displayObject = displayObject._iNext; + continue; + } + + if(displayObject instanceof PIXI.Sprite) + { + + var frame = displayObject.texture.frame; + + if(frame && frame.width && frame.height) + { + context.globalAlpha = displayObject.worldAlpha; + + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + + context.drawImage(displayObject.texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.y) * -frame.height, + frame.width, + frame.height); + } + } + else if(displayObject instanceof PIXI.Strip) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderStrip(displayObject); + } + else if(displayObject instanceof PIXI.TilingSprite) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderTilingSprite(displayObject); + } + else if(displayObject instanceof PIXI.CustomRenderable) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + displayObject.renderCanvas(this); + } + else if(displayObject instanceof PIXI.Graphics) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + PIXI.CanvasGraphics.renderGraphics(displayObject, context); + } + else if(displayObject instanceof PIXI.FilterBlock) + { + if(displayObject.data instanceof PIXI.Graphics) + { + var mask = displayObject.data; + + if(displayObject.open) + { + context.save(); + + var cacheAlpha = mask.alpha; + var maskTransform = mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(mask, context); + context.clip(); + + mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } + } + else + { + // only masks supported right now! + } + } + // count++ + displayObject = displayObject._iNext; + + + } + while(displayObject != testObject) + + +} + +/** + * Renders a flat strip + * + * @method renderStripFlat + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) +{ + var context = this.context; + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + + context.beginPath(); + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + }; + + context.fillStyle = "#FF0000"; + context.fill(); + context.closePath(); +} + +/** + * Renders a tiling sprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tilingsprite to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) +{ + var context = this.context; + + context.globalAlpha = sprite.worldAlpha; + + if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); + + context.beginPath(); + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + // offset + context.scale(tileScale.x,tileScale.y); + context.translate(tilePosition.x, tilePosition.y); + + context.fillStyle = sprite.__tilePattern; + context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); + + context.scale(1/tileScale.x, 1/tileScale.y); + context.translate(-tilePosition.x, -tilePosition.y); + + context.closePath(); +} + +/** + * Renders a strip + * + * @method renderStrip + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStrip = function(strip) +{ + var context = this.context; + + // draw triangles!! + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; + var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; + + + context.save(); + context.beginPath(); + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + context.closePath(); + + context.clip(); + + + // Compute matrix transform + var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; + var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; + var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; + var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; + var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; + var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; + var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; + + + + + context.transform(delta_a/delta, delta_d/delta, + delta_b/delta, delta_e/delta, + delta_c/delta, delta_f/delta); + + context.drawImage(strip.texture.baseTexture.source, 0, 0); + context.restore(); + }; + +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A set of functions used by the canvas renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.CanvasGraphics = function() +{ + +} + + +/* + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphics = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + for (var i=0; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); + + context.lineWidth = data.lineWidth; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + + if(data.fillColor || data.fillColor === 0) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fillRect(points[0], points[1], points[2], points[3]); + + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.strokeRect(points[0], points[1], points[2], points[3]); + } + + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + + }; +} + +/* + * Renders a graphics mask + * + * @static + * @private + * @method renderGraphicsMask + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + var len = graphics.graphicsData.length; + if(len === 0)return; + + if(len > 1) + { + len = 1; + console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") + } + + for (var i=0; i < 1; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + } + else if(data.type == PIXI.Graphics.RECT) + { + context.beginPath(); + context.rect(points[0], points[1], points[2], points[3]); + context.closePath(); + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + + + }; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * It is important to know that with the webGL renderer only simple polys can be filled at this stage + * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png + * + * @class Graphics + * @extends DisplayObjectContainer + * @constructor + */ +PIXI.Graphics = function() +{ + PIXI.DisplayObjectContainer.call( this ); + + this.renderable = true; + + /** + * The alpha of the fill of this graphics object + * + * @property fillAlpha + * @type Number + */ + this.fillAlpha = 1; + + /** + * The width of any lines drawn + * + * @property lineWidth + * @type Number + */ + this.lineWidth = 0; + + /** + * The color of any lines drawn + * + * @property lineColor + * @type String + */ + this.lineColor = "black"; + + /** + * Graphics data + * + * @property graphicsData + * @type Array + * @private + */ + this.graphicsData = []; + + /** + * Current path + * + * @property currentPath + * @type Object + * @private + */ + this.currentPath = {points:[]}; +} + +// constructor +PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Graphics.prototype.constructor = PIXI.Graphics; + +/** + * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. + * + * @method lineStyle + * @param lineWidth {Number} width of the line to draw, will update the object's stored style + * @param color {Number} color of the line to draw, will update the object's stored style + * @param alpha {Number} alpha of the line to draw, will update the object's stored style + */ +PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.lineWidth = lineWidth || 0; + this.lineColor = color || 0; + this.lineAlpha = (alpha == undefined) ? 1 : alpha; + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.graphicsData.push(this.currentPath); +} + +/** + * Moves the current drawing position to (x, y). + * + * @method moveTo + * @param x {Number} the X coord to move to + * @param y {Number} the Y coord to move to + */ +PIXI.Graphics.prototype.moveTo = function(x, y) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.currentPath.points.push(x, y); + + this.graphicsData.push(this.currentPath); +} + +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coord to draw to + * @param y {Number} the Y coord to draw to + */ +PIXI.Graphics.prototype.lineTo = function(x, y) +{ + this.currentPath.points.push(x, y); + this.dirty = true; +} + +/** + * Specifies a simple one-color fill that subsequent calls to other Graphics methods + * (such as lineTo() or drawCircle()) use when drawing. + * + * @method beginFill + * @param color {uint} the color of the fill + * @param alpha {Number} the alpha + */ +PIXI.Graphics.prototype.beginFill = function(color, alpha) +{ + this.filling = true; + this.fillColor = color || 0; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; +} + +/** + * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. + * + * @method endFill + */ +PIXI.Graphics.prototype.endFill = function() +{ + this.filling = false; + this.fillColor = null; + this.fillAlpha = 1; +} + +/** + * @method drawRect + * + * @param x {Number} The X coord of the top-left of the rectangle + * @param y {Number} The Y coord of the top-left of the rectangle + * @param width {Number} The width of the rectangle + * @param height {Number} The height of the rectangle + */ +PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.RECT}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws a circle. + * + * @method drawCircle + * @param x {Number} The X coord of the center of the circle + * @param y {Number} The Y coord of the center of the circle + * @param radius {Number} The radius of the circle + */ +PIXI.Graphics.prototype.drawCircle = function( x, y, radius) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws an elipse. + * + * @method drawElipse + * @param x {Number} + * @param y {Number} + * @param width {Number} + * @param height {Number} + */ +PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.ELIP}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. + * + * @method clear + */ +PIXI.Graphics.prototype.clear = function() +{ + this.lineWidth = 0; + this.filling = false; + + this.dirty = true; + this.clearDirty = true; + this.graphicsData = []; + + this.bounds = null//new PIXI.Rectangle(); +} + + +PIXI.Graphics.prototype.updateFilterBounds = function() +{ + if(!this.bounds) + { + var minX = Infinity; + var maxX = -Infinity; + + var minY = Infinity; + var maxY = -Infinity; + + var points, x, y; + + for (var i = 0; i < this.graphicsData.length; i++) { + + + var data = this.graphicsData[i]; + var type = data.type; + var lineWidth = data.lineWidth; + + points = data.points; + + if(type === PIXI.Graphics.RECT) + { + x = points.x - lineWidth/2; + y = points.y - lineWidth/2; + var width = points.width + lineWidth; + var height = points.height + lineWidth; + + minX = x < minX ? x : minX; + maxX = x + width > maxX ? x + width : maxX; + + minY = y < minY ? x : minY; + maxY = y + height > maxY ? y + height : maxY; + } + else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + { + x = points.x; + y = points.y; + var radius = points.radius + lineWidth/2; + + minX = x - radius < minX ? x - radius : minX; + maxX = x + radius > maxX ? x + radius : maxX; + + minY = y - radius < minY ? y - radius : minY; + maxY = y + radius > maxY ? y + radius : maxY; + } + else + { + // POLY + for (var j = 0; j < points.length; j+=2) + { + + x = points[j]; + y = points[j+1]; + + minX = x-lineWidth < minX ? x-lineWidth : minX; + maxX = x+lineWidth > maxX ? x+lineWidth : maxX; + + minY = y-lineWidth < minY ? y-lineWidth : minY; + maxY = y+lineWidth > maxY ? y+lineWidth : maxY; + }; + } + + }; + + this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + + } + +// console.log(this.bounds); +} + +// SOME TYPES: +PIXI.Graphics.POLY = 0; +PIXI.Graphics.RECT = 1; +PIXI.Graphics.CIRC = 2; +PIXI.Graphics.ELIP = 3; + +/** + * @author Mat Groves http://matgroves.com/ + */ + +PIXI.Strip = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + this.texture = texture; + this.blendMode = PIXI.blendModes.NORMAL; + + try + { + this.uvs = new Float32Array([0, 1, + 1, 1, + 1, 0, 0,1]); + + this.verticies = new Float32Array([0, 0, + 0,0, + 0,0, 0, + 0, 0]); + + this.colors = new Float32Array([1, 1, 1, 1]); + + this.indices = new Uint16Array([0, 1, 2, 3]); + } + catch(error) + { + this.uvs = [0, 1, + 1, 1, + 1, 0, 0,1]; + + this.verticies = [0, 0, + 0,0, + 0,0, 0, + 0, 0]; + + this.colors = [1, 1, 1, 1]; + + this.indices = [0, 1, 2, 3]; + } + + + /* + this.uvs = new Float32Array() + this.verticies = new Float32Array() + this.colors = new Float32Array() + this.indices = new Uint16Array() +*/ + this.width = width; + this.height = height; + + // load the texture! + if(texture.baseTexture.hasLoaded) + { + this.width = this.texture.frame.width; + this.height = this.texture.frame.height; + this.updateFrame = true; + } + else + { + this.onTextureUpdateBind = this.onTextureUpdate.bind(this); + this.texture.addEventListener( 'update', this.onTextureUpdateBind ); + } + + this.renderable = true; +} + +// constructor +PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Strip.prototype.constructor = PIXI.Strip; + +PIXI.Strip.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.width = texture.frame.width; + this.height = texture.frame.height; + this.updateFrame = true; +} + +PIXI.Strip.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} +// some helper functions.. + + +/** + * @author Mat Groves http://matgroves.com/ + */ + + +PIXI.Rope = function(texture, points) +{ + PIXI.Strip.call( this, texture ); + this.points = points; + + try + { + this.verticies = 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); + } + catch(error) + { + this.verticies = verticies + + this.uvs = uvs + this.colors = colors + this.indices = indices + } + + this.refresh(); +} + + +// constructor +PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); +PIXI.Rope.prototype.constructor = PIXI.Rope; + +PIXI.Rope.prototype.refresh = function() +{ + var points = this.points; + if(points.length < 1)return; + + var uvs = this.uvs + var indices = this.indices; + var colors = this.colors; + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + + uvs[0] = 0 + uvs[1] = 1 + uvs[2] = 0 + uvs[3] = 1 + + colors[0] = 1; + colors[1] = 1; + + indices[0] = 0; + indices[1] = 1; + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + // time to do some smart drawing! + var amount = i/(total-1) + + if(i%2) + { + uvs[index] = amount; + uvs[index+1] = 0; + + uvs[index+2] = amount + uvs[index+3] = 1 + + } + else + { + uvs[index] = amount + uvs[index+1] = 0 + + uvs[index+2] = amount + uvs[index+3] = 1 + } + + index = i * 2; + colors[index] = 1; + colors[index+1] = 1; + + index = i * 2; + indices[index] = index; + indices[index + 1] = index + 1; + + lastPoint = point; + } +} + +PIXI.Rope.prototype.updateTransform = function() +{ + + var points = this.points; + if(points.length < 1)return; + + var verticies = this.verticies + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + verticies[0] = point.x + perp.x + verticies[1] = point.y + perp.y //+ 200 + verticies[2] = point.x - perp.x + verticies[3] = point.y - perp.y//+200 + // time to do some smart drawing! + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + + if(i < points.length-1) + { + nextPoint = points[i+1]; + } + else + { + nextPoint = point + } + + perp.y = -(nextPoint.x - lastPoint.x); + perp.x = nextPoint.y - lastPoint.y; + + var ratio = (1 - (i / (total-1))) * 10; + if(ratio > 1)ratio = 1; + + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); + var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; + perp.x /= perpLength; + perp.y /= perpLength; + + perp.x *= num; + perp.y *= num; + + verticies[index] = point.x + perp.x + verticies[index+1] = point.y + perp.y + verticies[index+2] = point.x - perp.x + verticies[index+3] = point.y - perp.y + + lastPoint = point; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); +} + +PIXI.Rope.prototype.setTexture = function(texture) +{ + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * A tiling sprite is a fast way of rendering a tiling image + * + * @class TilingSprite + * @extends DisplayObjectContainer + * @constructor + * @param texture {Texture} the texture of the tiling sprite + * @param width {Number} the width of the tiling sprite + * @param height {Number} the height of the tiling sprite + */ +PIXI.TilingSprite = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * The texture that the sprite is using + * + * @property texture + * @type Texture + */ + this.texture = texture; + + /** + * The width of the tiling sprite + * + * @property width + * @type Number + */ + this.width = width; + + /** + * The height of the tiling sprite + * + * @property height + * @type Number + */ + this.height = height; + + /** + * The scaling of the image that is being tiled + * + * @property tileScale + * @type Point + */ + this.tileScale = new PIXI.Point(1,1); + + /** + * The offset position of the image that is being tiled + * + * @property tilePosition + * @type Point + */ + this.tilePosition = new PIXI.Point(0,0); + + this.renderable = true; + + this.blendMode = PIXI.blendModes.NORMAL +} + +// constructor +PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; + +/** + * Sets the texture of the tiling sprite + * + * @method setTexture + * @param texture {Texture} The PIXI texture that is displayed by the sprite + */ +PIXI.TilingSprite.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + +/** + * When the texture is updated, this event will fire to update the frame + * + * @method onTextureUpdate + * @param event + * @private + */ +PIXI.TilingSprite.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi + * + * Awesome JS run time provided by EsotericSoftware + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +/** + * A class that enables the you to import and run your spine animations in pixi. + * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class + * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source + * + * @class Spine + * @extends DisplayObjectContainer + * @constructor + * @param url {String} The url of the spine anim file to be used + */ +PIXI.Spine = function (url) { + PIXI.DisplayObjectContainer.call(this); + + this.spineData = PIXI.AnimCache[url]; + + if (!this.spineData) { + throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); + } + + this.skeleton = new spine.Skeleton(this.spineData); + this.skeleton.updateWorldTransform(); + + this.stateData = new spine.AnimationStateData(this.spineData); + this.state = new spine.AnimationState(this.stateData); + + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.Spine.prototype.constructor = PIXI.Spine; + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); + this.state.apply(this.skeleton); + this.skeleton.updateWorldTransform(); + + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } + + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; + } + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; + } + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; + +/* + * Awesome JS run time provided by EsotericSoftware + * + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +var spine = {}; + +spine.BoneData = function (name, parent) { + this.name = name; + this.parent = parent; +}; +spine.BoneData.prototype = { + length: 0, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1 +}; + +spine.SlotData = function (name, boneData) { + this.name = name; + this.boneData = boneData; +}; +spine.SlotData.prototype = { + r: 1, g: 1, b: 1, a: 1, + attachmentName: null +}; + +spine.Bone = function (boneData, parent) { + this.data = boneData; + this.parent = parent; + this.setToSetupPose(); +}; +spine.Bone.yDown = false; +spine.Bone.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + m00: 0, m01: 0, worldX: 0, // a b x + m10: 0, m11: 0, worldY: 0, // c d y + worldRotation: 0, + worldScaleX: 1, worldScaleY: 1, + updateWorldTransform: function (flipX, flipY) { + var parent = this.parent; + if (parent != null) { + this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; + this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; + this.worldScaleX = parent.worldScaleX * this.scaleX; + this.worldScaleY = parent.worldScaleY * this.scaleY; + this.worldRotation = parent.worldRotation + this.rotation; + } else { + this.worldX = this.x; + this.worldY = this.y; + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + this.worldRotation = this.rotation; + } + var radians = this.worldRotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + this.m00 = cos * this.worldScaleX; + this.m10 = sin * this.worldScaleX; + this.m01 = -sin * this.worldScaleY; + this.m11 = cos * this.worldScaleY; + if (flipX) { + this.m00 = -this.m00; + this.m01 = -this.m01; + } + if (flipY) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + if (spine.Bone.yDown) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + }, + setToSetupPose: function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + } +}; + +spine.Slot = function (slotData, skeleton, bone) { + this.data = slotData; + this.skeleton = skeleton; + this.bone = bone; + this.setToSetupPose(); +}; +spine.Slot.prototype = { + r: 1, g: 1, b: 1, a: 1, + _attachmentTime: 0, + attachment: null, + setAttachment: function (attachment) { + this.attachment = attachment; + this._attachmentTime = this.skeleton.time; + }, + setAttachmentTime: function (time) { + this._attachmentTime = this.skeleton.time - time; + }, + getAttachmentTime: function () { + return this.skeleton.time - this._attachmentTime; + }, + setToSetupPose: function () { + var data = this.data; + this.r = data.r; + this.g = data.g; + this.b = data.b; + this.a = data.a; + + var slotDatas = this.skeleton.data.slots; + for (var i = 0, n = slotDatas.length; i < n; i++) { + if (slotDatas[i] == data) { + this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); + break; + } + } + } +}; + +spine.Skin = function (name) { + this.name = name; + this.attachments = {}; +}; +spine.Skin.prototype = { + addAttachment: function (slotIndex, name, attachment) { + this.attachments[slotIndex + ":" + name] = attachment; + }, + getAttachment: function (slotIndex, name) { + return this.attachments[slotIndex + ":" + name]; + }, + _attachAll: function (skeleton, oldSkin) { + for (var key in oldSkin.attachments) { + var colon = key.indexOf(":"); + var slotIndex = parseInt(key.substring(0, colon)); + var name = key.substring(colon + 1); + var slot = skeleton.slots[slotIndex]; + if (slot.attachment && slot.attachment.name == name) { + var attachment = this.getAttachment(slotIndex, name); + if (attachment) slot.setAttachment(attachment); + } + } + } +}; + +spine.Animation = function (name, timelines, duration) { + this.name = name; + this.timelines = timelines; + this.duration = duration; +}; +spine.Animation.prototype = { + apply: function (skeleton, time, loop) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, 1); + }, + mix: function (skeleton, time, loop, alpha) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, alpha); + } +}; + +spine.binarySearch = function (values, target, step) { + var low = 0; + var high = Math.floor(values.length / step) - 2; + if (high == 0) return step; + var current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } +}; +spine.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; +}; + +spine.Curves = function (frameCount) { + this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... + this.curves.length = (frameCount - 1) * 6; +}; +spine.Curves.prototype = { + setLinear: function (frameIndex) { + this.curves[frameIndex * 6] = 0/*LINEAR*/; + }, + setStepped: function (frameIndex) { + this.curves[frameIndex * 6] = -1/*STEPPED*/; + }, + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { + var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; + var subdiv_step2 = subdiv_step * subdiv_step; + var subdiv_step3 = subdiv_step2 * subdiv_step; + var pre1 = 3 * subdiv_step; + var pre2 = 3 * subdiv_step2; + var pre4 = 6 * subdiv_step2; + var pre5 = 6 * subdiv_step3; + var tmp1x = -cx1 * 2 + cx2; + var tmp1y = -cy1 * 2 + cy2; + var tmp2x = (cx1 - cx2) * 3 + 1; + var tmp2y = (cy1 - cy2) * 3 + 1; + var i = frameIndex * 6; + var curves = this.curves; + curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; + curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; + curves[i + 4] = tmp2x * pre5; + curves[i + 5] = tmp2y * pre5; + }, + getCurvePercent: function (frameIndex, percent) { + percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); + var curveIndex = frameIndex * 6; + var curves = this.curves; + var dfx = curves[curveIndex]; + if (!dfx/*LINEAR*/) return percent; + if (dfx == -1/*STEPPED*/) return 0; + var dfy = curves[curveIndex + 1]; + var ddfx = curves[curveIndex + 2]; + var ddfy = curves[curveIndex + 3]; + var dddfx = curves[curveIndex + 4]; + var dddfy = curves[curveIndex + 5]; + var x = dfx, y = dfy; + var i = 10/*BEZIER_SEGMENTS*/ - 2; + while (true) { + if (x >= percent) { + var lastX = x - dfx; + var lastY = y - dfy; + return lastY + (y - lastY) * (percent - lastX) / (x - lastX); + } + if (i == 0) break; + i--; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +}; + +spine.RotateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, angle, ... + this.frames.length = frameCount * 2; +}; +spine.RotateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, angle) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = angle; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 2]) { // Time is after last frame. + var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 2); + var lastFrameValue = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); + + var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +}; + +spine.TranslateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.TranslateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; + } +}; + +spine.ScaleTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.ScaleTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; + } +}; + +spine.ColorTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, r, g, b, a, ... + this.frames.length = frameCount * 5; +}; +spine.ColorTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 5; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = r; + this.frames[frameIndex + 2] = g; + this.frames[frameIndex + 3] = b; + this.frames[frameIndex + 4] = a; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var slot = skeleton.slots[this.slotIndex]; + + if (time >= frames[frames.length - 5]) { // Time is after last frame. + var i = frames.length - 1; + slot.r = frames[i - 3]; + slot.g = frames[i - 2]; + slot.b = frames[i - 1]; + slot.a = frames[i]; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 5); + var lastFrameR = frames[frameIndex - 4]; + var lastFrameG = frames[frameIndex - 3]; + var lastFrameB = frames[frameIndex - 2]; + var lastFrameA = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); + + var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; + var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; + var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; + var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +}; + +spine.AttachmentTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, ... + this.frames.length = frameCount; + this.attachmentNames = []; // time, ... + this.attachmentNames.length = frameCount; +}; +spine.AttachmentTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = spine.binarySearch(frames, time, 1) - 1; + + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); + } +}; + +spine.SkeletonData = function () { + this.bones = []; + this.slots = []; + this.skins = []; + this.animations = []; +}; +spine.SkeletonData.prototype = { + defaultSkin: null, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + if (slots[i].name == slotName) return slot[i]; + } + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + }, + /** @return May be null. */ + findSkin: function (skinName) { + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) + if (skins[i].name == skinName) return skins[i]; + return null; + }, + /** @return May be null. */ + findAnimation: function (animationName) { + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) + if (animations[i].name == animationName) return animations[i]; + return null; + } +}; + +spine.Skeleton = function (skeletonData) { + this.data = skeletonData; + + this.bones = []; + for (var i = 0, n = skeletonData.bones.length; i < n; i++) { + var boneData = skeletonData.bones[i]; + var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; + this.bones.push(new spine.Bone(boneData, parent)); + } + + this.slots = []; + this.drawOrder = []; + for (var i = 0, n = skeletonData.slots.length; i < n; i++) { + var slotData = skeletonData.slots[i]; + var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; + var slot = new spine.Slot(slotData, this, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } +}; +spine.Skeleton.prototype = { + x: 0, y: 0, + skin: null, + r: 1, g: 1, b: 1, a: 1, + time: 0, + flipX: false, flipY: false, + /** Updates the world transform for each bone. */ + updateWorldTransform: function () { + var flipX = this.flipX; + var flipY = this.flipY; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].updateWorldTransform(flipX, flipY); + }, + /** Sets the bones and slots to their setup pose values. */ + setToSetupPose: function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }, + setBonesToSetupPose: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + }, + setSlotsToSetupPose: function () { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(i); + }, + /** @return May return null. */ + getRootBone: function () { + return this.bones.length == 0 ? null : this.bones[0]; + }, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return slots[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + }, + setSkinByName: function (skinName) { + var skin = this.data.findSkin(skinName); + if (!skin) throw "Skin not found: " + skinName; + this.setSkin(skin); + }, + /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments + * from the new skin are attached if the corresponding attachment from the old skin was attached. + * @param newSkin May be null. */ + setSkin: function (newSkin) { + if (this.skin && newSkin) newSkin._attachAll(this, this.skin); + this.skin = newSkin; + }, + /** @return May be null. */ + getAttachmentBySlotName: function (slotName, attachmentName) { + return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); + }, + /** @return May be null. */ + getAttachmentBySlotIndex: function (slotIndex, attachmentName) { + if (this.skin) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }, + /** @param attachmentName May be null. */ + setAttachment: function (slotName, attachmentName) { + var slots = this.slots; + for (var i = 0, n = slots.size; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; + } + slot.setAttachment(attachment); + return; + } + } + throw "Slot not found: " + slotName; + }, + update: function (delta) { + time += delta; + } +}; + +spine.AttachmentType = { + region: 0 +}; + +spine.RegionAttachment = function () { + this.offset = []; + this.offset.length = 8; + this.uvs = []; + this.uvs.length = 8; +}; +spine.RegionAttachment.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + width: 0, height: 0, + rendererObject: null, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + setUVs: function (u, v, u2, v2, rotate) { + var uvs = this.uvs; + if (rotate) { + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v2; + uvs[4/*X3*/] = u; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v; + uvs[0/*X1*/] = u2; + uvs[1/*Y1*/] = v2; + } else { + uvs[0/*X1*/] = u; + uvs[1/*Y1*/] = v2; + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v; + uvs[4/*X3*/] = u2; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v2; + } + }, + updateOffset: function () { + var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; + var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; + var localX2 = localX + this.regionWidth * regionScaleX; + var localY2 = localY + this.regionHeight * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[0/*X1*/] = localXCos - localYSin; + offset[1/*Y1*/] = localYCos + localXSin; + offset[2/*X2*/] = localXCos - localY2Sin; + offset[3/*Y2*/] = localY2Cos + localXSin; + offset[4/*X3*/] = localX2Cos - localY2Sin; + offset[5/*Y3*/] = localY2Cos + localX2Sin; + offset[6/*X4*/] = localX2Cos - localYSin; + offset[7/*Y4*/] = localYCos + localX2Sin; + }, + computeVertices: function (x, y, bone, vertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00; + var m01 = bone.m01; + var m10 = bone.m10; + var m11 = bone.m11; + var offset = this.offset; + vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; + vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; + vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; + vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; + vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; + vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; + vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; + vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; + } +} + +spine.AnimationStateData = function (skeletonData) { + this.skeletonData = skeletonData; + this.animationToMixTime = {}; +}; +spine.AnimationStateData.prototype = { + defaultMix: 0, + setMixByName: function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (!from) throw "Animation not found: " + fromName; + var to = this.skeletonData.findAnimation(toName); + if (!to) throw "Animation not found: " + toName; + this.setMix(from, to, duration); + }, + setMix: function (from, to, duration) { + this.animationToMixTime[from.name + ":" + to.name] = duration; + }, + getMix: function (from, to) { + var time = this.animationToMixTime[from.name + ":" + to.name]; + return time ? time : this.defaultMix; + } +}; + +spine.AnimationState = function (stateData) { + this.data = stateData; + this.queue = []; +}; +spine.AnimationState.prototype = { + current: null, + previous: null, + currentTime: 0, + previousTime: 0, + currentLoop: false, + previousLoop: false, + mixTime: 0, + mixDuration: 0, + update: function (delta) { + this.currentTime += delta; + this.previousTime += delta; + this.mixTime += delta; + + if (this.queue.length > 0) { + var entry = this.queue[0]; + if (this.currentTime >= entry.delay) { + this._setAnimation(entry.animation, entry.loop); + this.queue.shift(); + } + } + }, + apply: function (skeleton) { + if (!this.current) return; + if (this.previous) { + this.previous.apply(skeleton, this.previousTime, this.previousLoop); + var alpha = this.mixTime / this.mixDuration; + if (alpha >= 1) { + alpha = 1; + this.previous = null; + } + this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); + } else + this.current.apply(skeleton, this.currentTime, this.currentLoop); + }, + clearAnimation: function () { + this.previous = null; + this.current = null; + this.queue.length = 0; + }, + _setAnimation: function (animation, loop) { + this.previous = null; + if (animation && this.current) { + this.mixDuration = this.data.getMix(this.current, animation); + if (this.mixDuration > 0) { + this.mixTime = 0; + this.previous = this.current; + this.previousTime = this.currentTime; + this.previousLoop = this.currentLoop; + } + } + this.current = animation; + this.currentLoop = loop; + this.currentTime = 0; + }, + /** @see #setAnimation(Animation, Boolean) */ + setAnimationByName: function (animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.setAnimation(animation, loop); + }, + /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. + * @param animation May be null. */ + setAnimation: function (animation, loop) { + this.queue.length = 0; + this._setAnimation(animation, loop); + }, + /** @see #addAnimation(Animation, Boolean, Number) */ + addAnimationByName: function (animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.addAnimation(animation, loop, delay); + }, + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimation: function (animation, loop, delay) { + var entry = {}; + entry.animation = animation; + entry.loop = loop; + + if (!delay || delay <= 0) { + var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; + if (previousAnimation != null) + delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); + else + delay = 0; + } + entry.delay = delay; + + this.queue.push(entry); + }, + /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ + isComplete: function () { + return !this.current || this.currentTime >= this.current.duration; + } +}; + +spine.SkeletonJson = function (attachmentLoader) { + this.attachmentLoader = attachmentLoader; +}; +spine.SkeletonJson.prototype = { + scale: 1, + readSkeletonData: function (root) { + var skeletonData = new spine.SkeletonData(); + + // Bones. + var bones = root["bones"]; + for (var i = 0, n = bones.length; i < n; i++) { + var boneMap = bones[i]; + var parent = null; + if (boneMap["parent"]) { + parent = skeletonData.findBone(boneMap["parent"]); + if (!parent) throw "Parent bone not found: " + boneMap["parent"]; + } + var boneData = new spine.BoneData(boneMap["name"], parent); + boneData.length = (boneMap["length"] || 0) * this.scale; + boneData.x = (boneMap["x"] || 0) * this.scale; + boneData.y = (boneMap["y"] || 0) * this.scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap["scaleX"] || 1; + boneData.scaleY = boneMap["scaleY"] || 1; + skeletonData.bones.push(boneData); + } + + // Slots. + var slots = root["slots"]; + for (var i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + var boneData = skeletonData.findBone(slotMap["bone"]); + if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; + var slotData = new spine.SlotData(slotMap["name"], boneData); + + var color = slotMap["color"]; + if (color) { + slotData.r = spine.SkeletonJson.toColor(color, 0); + slotData.g = spine.SkeletonJson.toColor(color, 1); + slotData.b = spine.SkeletonJson.toColor(color, 2); + slotData.a = spine.SkeletonJson.toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + + skeletonData.slots.push(slotData); + } + + // Skins. + var skins = root["skins"]; + for (var skinName in skins) { + if (!skins.hasOwnProperty(skinName)) continue; + var skinMap = skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + if (!skinMap.hasOwnProperty(slotName)) continue; + var slotIndex = skeletonData.findSlotIndex(slotName); + var slotEntry = skinMap[slotName]; + for (var attachmentName in slotEntry) { + if (!slotEntry.hasOwnProperty(attachmentName)) continue; + var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); + if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + + // Animations. + var animations = root["animations"]; + for (var animationName in animations) { + if (!animations.hasOwnProperty(animationName)) continue; + this.readAnimation(animationName, animations[animationName], skeletonData); + } + + return skeletonData; + }, + readAttachment: function (skin, name, map) { + name = map["name"] || name; + + var type = spine.AttachmentType[map["type"] || "region"]; + + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); + attachment.x = (map["x"] || 0) * this.scale; + attachment.y = (map["y"] || 0) * this.scale; + attachment.scaleX = map["scaleX"] || 1; + attachment.scaleY = map["scaleY"] || 1; + attachment.rotation = map["rotation"] || 0; + attachment.width = (map["width"] || 32) * this.scale; + attachment.height = (map["height"] || 32) * this.scale; + attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; + } + + throw "Unknown attachment type: " + type; + }, + + readAnimation: function (name, map, skeletonData) { + var timelines = []; + var duration = 0; + + var bones = map["bones"]; + for (var boneName in bones) { + if (!bones.hasOwnProperty(boneName)) continue; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw "Bone not found: " + boneName; + var boneMap = bones[boneName]; + + for (var timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + var values = boneMap[timelineName]; + if (timelineName == "rotate") { + var timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + + } else if (timelineName == "translate" || timelineName == "scale") { + var timeline; + var timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var x = (valueMap["x"] || 0) * timelineScale; + var y = (valueMap["y"] || 0) * timelineScale; + timeline.setFrame(frameIndex, valueMap["time"], x, y); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); + + } else + throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; + } + } + var slots = map["slots"]; + for (var slotName in slots) { + if (!slots.hasOwnProperty(slotName)) continue; + var slotMap = slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + + for (var timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + var values = slotMap[timelineName]; + if (timelineName == "color") { + var timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var color = valueMap["color"]; + var r = spine.SkeletonJson.toColor(color, 0); + var g = spine.SkeletonJson.toColor(color, 1); + var b = spine.SkeletonJson.toColor(color, 2); + var a = spine.SkeletonJson.toColor(color, 3); + timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); + + } else if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + + } else + throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; + } + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + } +}; +spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { + var curve = valueMap["curve"]; + if (!curve) return; + if (curve == "stepped") + timeline.curves.setStepped(frameIndex); + else if (curve instanceof Array) + timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); +}; +spine.SkeletonJson.toColor = function (hexString, colorIndex) { + if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; + return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; +}; + +spine.Atlas = function (atlasText, textureLoader) { + this.textureLoader = textureLoader; + this.pages = []; + this.regions = []; + + var reader = new spine.AtlasReader(atlasText); + var tuple = []; + tuple.length = 4; + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) break; + line = reader.trim(line); + if (line.length == 0) + page = null; + else if (!page) { + page = new spine.AtlasPage(); + page.name = line; + + page.format = spine.Atlas.Format[reader.readValue()]; + + reader.readTuple(tuple); + page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; + page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; + + var direction = reader.readValue(); + page.uWrap = spine.Atlas.TextureWrap.clampToEdge; + page.vWrap = spine.Atlas.TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "y") + page.vWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; + + textureLoader.load(page, line); + + this.pages.push(page); + + } else { + var region = new spine.AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + this.regions.push(region); + } + } +}; +spine.Atlas.prototype = { + findRegion: function (name) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + }, + dispose: function () { + var pages = this.pages; + for (var i = 0, n = pages.length; i < n; i++) + this.textureLoader.unload(pages[i].rendererObject); + }, + updateUVs: function (page) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) { + var region = regions[i]; + if (region.page != page) continue; + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.rotate) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + } + } +}; + +spine.Atlas.Format = { + alpha: 0, + intensity: 1, + luminanceAlpha: 2, + rgb565: 3, + rgba4444: 4, + rgb888: 5, + rgba8888: 6 +}; + +spine.Atlas.TextureFilter = { + nearest: 0, + linear: 1, + mipMap: 2, + mipMapNearestNearest: 3, + mipMapLinearNearest: 4, + mipMapNearestLinear: 5, + mipMapLinearLinear: 6 +}; + +spine.Atlas.TextureWrap = { + mirroredRepeat: 0, + clampToEdge: 1, + repeat: 2 +}; + +spine.AtlasPage = function () {}; +spine.AtlasPage.prototype = { + name: null, + format: null, + minFilter: null, + magFilter: null, + uWrap: null, + vWrap: null, + rendererObject: null, + width: 0, + height: 0 +}; + +spine.AtlasRegion = function () {}; +spine.AtlasRegion.prototype = { + page: null, + name: null, + x: 0, y: 0, + width: 0, height: 0, + u: 0, v: 0, u2: 0, v2: 0, + offsetX: 0, offsetY: 0, + originalWidth: 0, originalHeight: 0, + index: 0, + rotate: false, + splits: null, + pads: null, +}; + +spine.AtlasReader = function (text) { + this.lines = text.split(/\r\n|\r|\n/); +}; +spine.AtlasReader.prototype = { + index: 0, + trim: function (value) { + return value.replace(/^\s+|\s+$/g, ""); + }, + readLine: function () { + if (this.index >= this.lines.length) return null; + return this.lines[this.index++]; + }, + readValue: function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + return this.trim(line.substring(colon + 1)); + }, + /** Returns the number of tuple values read (2 or 4). */ + readTuple: function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + var i = 0, lastMatch= colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) { + if (i == 0) throw "Invalid line: " + line; + break; + } + tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = this.trim(line.substring(lastMatch)); + return i + 1; + } +} + +spine.AtlasAttachmentLoader = function (atlas) { + this.atlas = atlas; +} +spine.AtlasAttachmentLoader.prototype = { + newAttachment: function (skin, type, name) { + switch (type) { + case spine.AttachmentType.region: + var region = this.atlas.findRegion(name); + if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; + var attachment = new spine.RegionAttachment(name); + attachment.rendererObject = region; + attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + throw "Unknown attachment type: " + type; + } +} + +PIXI.AnimCache = {}; +spine.Bone.yDown = true; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * This object is one that will allow you to specify custom rendering functions based on render type + * + * @class CustomRenderable + * @extends DisplayObject + * @constructor + */ +PIXI.CustomRenderable = function() +{ + PIXI.DisplayObject.call( this ); + + this.renderable = true; +} + +// constructor +PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; + +/** + * If this object is being rendered by a CanvasRenderer it will call this callback + * + * @method renderCanvas + * @param renderer {CanvasRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback to initialize + * + * @method initWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.initWebGL = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback + * + * @method renderWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) +{ + // not sure if both needed? but ya have for now! + // override! +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.BaseTextureCache = {}; +PIXI.texturesToUpdate = []; +PIXI.texturesToDestroy = []; + +/** + * A texture stores the information that represents an image. All textures have a base texture + * + * @class BaseTexture + * @uses EventTarget + * @constructor + * @param source {String} the source object (image or canvas) + */ +PIXI.BaseTexture = function(source) +{ + PIXI.EventTarget.call( this ); + + /** + * [read-only] The width of the base texture set when the image has loaded + * + * @property width + * @type Number + * @readOnly + */ + this.width = 100; + + /** + * [read-only] The height of the base texture set when the image has loaded + * + * @property height + * @type Number + * @readOnly + */ + this.height = 100; + + /** + * [read-only] Describes if the base texture has loaded or not + * + * @property hasLoaded + * @type Boolean + * @readOnly + */ + this.hasLoaded = false; + + /** + * The source that is loaded to create the texture + * + * @property source + * @type Image + */ + this.source = source; + + if(!source)return; + + if(this.source instanceof Image || this.source instanceof HTMLImageElement) + { + if(this.source.complete) + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + else + { + + var scope = this; + this.source.onload = function(){ + + scope.hasLoaded = true; + scope.width = scope.source.width; + scope.height = scope.source.height; + + // add it to somewhere... + PIXI.texturesToUpdate.push(scope); + scope.dispatchEvent( { type: 'loaded', content: scope } ); + } + // this.image.src = imageUrl; + } + } + else + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + + this._powerOf2 = false; +} + +PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; + +/** + * Destroys this base texture + * + * @method destroy + */ +PIXI.BaseTexture.prototype.destroy = function() +{ + if(this.source instanceof Image) + { + this.source.src = null; + } + this.source = null; + PIXI.texturesToDestroy.push(this); +} + +/** + * Helper function that returns a base texture based on an image url + * If the image is not in the base texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @return BaseTexture + */ +PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) +{ + var baseTexture = PIXI.BaseTextureCache[imageUrl]; + if(!baseTexture) + { + // new Image() breaks tex loading in some versions of Chrome. + // See https://code.google.com/p/chromium/issues/detail?id=238071 + var image = new Image();//document.createElement('img'); + if (crossorigin) + { + image.crossOrigin = ''; + } + image.src = imageUrl; + baseTexture = new PIXI.BaseTexture(image); + PIXI.BaseTextureCache[imageUrl] = baseTexture; + } + + return baseTexture; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.TextureCache = {}; +PIXI.FrameCache = {}; + +/** + * A texture stores the information that represents an image or part of an image. It cannot be added + * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used + * + * @class Texture + * @uses EventTarget + * @constructor + * @param baseTexture {BaseTexture} The base texture source to create the texture from + * @param frame {Rectangle} The rectangle frame of the texture to show + */ +PIXI.Texture = function(baseTexture, frame) +{ + PIXI.EventTarget.call( this ); + + if(!frame) + { + this.noFrame = true; + frame = new PIXI.Rectangle(0,0,1,1); + } + + if(baseTexture instanceof PIXI.Texture) + baseTexture = baseTexture.baseTexture; + + /** + * The base texture of this texture + * + * @property baseTexture + * @type BaseTexture + */ + this.baseTexture = baseTexture; + + /** + * The frame specifies the region of the base texture that this texture uses + * + * @property frame + * @type Rectangle + */ + this.frame = frame; + + /** + * The trim point + * + * @property trim + * @type Point + */ + this.trim = new PIXI.Point(); + + this.scope = this; + + if(baseTexture.hasLoaded) + { + if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + //console.log(frame) + + this.setFrame(frame); + } + else + { + var scope = this; + baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); + } +} + +PIXI.Texture.prototype.constructor = PIXI.Texture; + +/** + * Called when the base texture is loaded + * + * @method onBaseTextureLoaded + * @param event + * @private + */ +PIXI.Texture.prototype.onBaseTextureLoaded = function(event) +{ + var baseTexture = this.baseTexture; + baseTexture.removeEventListener( 'loaded', this.onLoaded ); + + if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + this.noFrame = false; + this.width = this.frame.width; + this.height = this.frame.height; + + this.scope.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Destroys this texture + * + * @method destroy + * @param destroyBase {Boolean} Whether to destroy the base texture as well + */ +PIXI.Texture.prototype.destroy = function(destroyBase) +{ + if(destroyBase)this.baseTexture.destroy(); +} + +/** + * Specifies the rectangle region of the baseTexture + * + * @method setFrame + * @param frame {Rectangle} The frame of the texture to set it to + */ +PIXI.Texture.prototype.setFrame = function(frame) +{ + this.frame = frame; + this.width = frame.width; + this.height = frame.height; + + 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); + } + + this.updateFrame = true; + + PIXI.Texture.frameUpdates.push(this); + //this.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Helper function that returns a texture based on an image url + * If the image is not in the texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + * @return Texture + */ +PIXI.Texture.fromImage = function(imageUrl, crossorigin) +{ + var texture = PIXI.TextureCache[imageUrl]; + + if(!texture) + { + texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); + PIXI.TextureCache[imageUrl] = texture; + } + + return texture; +} + +/** + * Helper function that returns a texture based on a frame id + * If the frame id is not in the texture cache an error will be thrown + * + * @static + * @method fromFrame + * @param frameId {String} The frame id of the texture + * @return Texture + */ +PIXI.Texture.fromFrame = function(frameId) +{ + var texture = PIXI.TextureCache[frameId]; + if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); + return texture; +} + +/** + * Helper function that returns a texture based on a canvas element + * If the canvas is not in the texture cache it will be created and loaded + * + * @static + * @method fromCanvas + * @param canvas {Canvas} The canvas element source of the texture + * @return Texture + */ +PIXI.Texture.fromCanvas = function(canvas) +{ + var baseTexture = new PIXI.BaseTexture(canvas); + return new PIXI.Texture(baseTexture); +} + + +/** + * Adds a texture to the textureCache. + * + * @static + * @method addTextureToCache + * @param texture {Texture} + * @param id {String} the id that the texture will be stored against. + */ +PIXI.Texture.addTextureToCache = function(texture, id) +{ + PIXI.TextureCache[id] = texture; +} + +/** + * Remove a texture from the textureCache. + * + * @static + * @method removeTextureFromCache + * @param id {String} the id of the texture to be removed + * @return {Texture} the texture that was removed + */ +PIXI.Texture.removeTextureFromCache = function(id) +{ + var texture = PIXI.TextureCache[id] + PIXI.TextureCache[id] = null; + return texture; +} + +// this is more for webGL.. it contains updated frames.. +PIXI.Texture.frameUpdates = []; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. + + __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. + Otherwise black rectangles will be drawn instead. + + RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: + + var renderTexture = new PIXI.RenderTexture(800, 600); + var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); + sprite.position.x = 800/2; + sprite.position.y = 600/2; + sprite.anchor.x = 0.5; + sprite.anchor.y = 0.5; + renderTexture.render(sprite); + + Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: + + var doc = new PIXI.DisplayObjectContainer(); + doc.addChild(sprite); + renderTexture.render(doc); // Renders to center of renderTexture + + @class RenderTexture + @extends Texture + @constructor + @param width {Number} The width of the render texture + @param height {Number} The height of the render texture + */ +PIXI.RenderTexture = function(width, height) +{ + PIXI.EventTarget.call( this ); + + this.width = width || 100; + this.height = height || 100; + + this.indetityMatrix = PIXI.mat3.create(); + + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + if(PIXI.gl) + { + this.initWebGL(); + } + else + { + this.initCanvas(); + } +} + +PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); +PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; + +/** + * Initializes the webgl data for this texture + * + * @method initWebGL + * @private + */ +PIXI.RenderTexture.prototype.initWebGL = function() +{ + var gl = PIXI.gl; + this.glFramebuffer = gl.createFramebuffer(); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + this.glFramebuffer.width = this.width; + this.glFramebuffer.height = this.height; + + this.baseTexture = new PIXI.BaseTexture(); + + this.baseTexture.width = this.width; + this.baseTexture.height = this.height; + + this.baseTexture._glTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + this.baseTexture.isRender = true; + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); + + // create a projection matrix.. + this.projection = new PIXI.Point(this.width/2 , -this.height/2); + + // set the correct render function.. + this.render = this.renderWebGL; +} + + +PIXI.RenderTexture.prototype.resize = function(width, height) +{ + + this.width = width; + this.height = height; + + if(PIXI.gl) + { + this.projection.x = this.width/2 + this.projection.y = -this.height/2; + + var gl = PIXI.gl; + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + else + { + + this.frame.width = this.width + this.frame.height = this.height; + this.renderer.resize(this.width, this.height); + } +} + +/** + * Initializes the canvas data for this texture + * + * @method initCanvas + * @private + */ +PIXI.RenderTexture.prototype.initCanvas = function() +{ + this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); + + this.baseTexture = new PIXI.BaseTexture(this.renderer.view); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + this.render = this.renderCanvas; +} + +/** + * This function will draw the display object to the texture. + * + * @method renderWebGL + * @param displayObject {DisplayObject} The display object to render this texture on + * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn + * @private + */ +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +{ + var gl = PIXI.gl; + + // enable the alpha color mask.. + gl.colorMask(true, true, true, true); + + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + if(clear) + { + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + // THIS WILL MESS WITH HIT TESTING! + var children = displayObject.children; + + //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; + displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; + // modify to flip... + displayObject.worldTransform[4] = -1; + displayObject.worldTransform[5] = this.projection.y * -2; + + if(position) + { + displayObject.worldTransform[2] = position.x; + displayObject.worldTransform[5] -= position.y; + } + + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + + for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded + * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported + * sprite sheet data formats only include "JSON" at this time. Supported bitmap font + * data formats include "xml" and "fnt". + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.AssetLoader = function(assetURLs, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The array of asset URLs that are going to be loaded + * + * @property assetURLs + * @type Array + */ + this.assetURLs = assetURLs; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * Maps file extension to loader types + * + * @property loadersByType + * @type Object + */ + this.loadersByType = { + "jpg": PIXI.ImageLoader, + "jpeg": PIXI.ImageLoader, + "png": PIXI.ImageLoader, + "gif": PIXI.ImageLoader, + "json": PIXI.JsonLoader, + "anim": PIXI.SpineLoader, + "xml": PIXI.BitmapFontLoader, + "fnt": PIXI.BitmapFontLoader + }; + + +}; + +/** + * Fired when an item has loaded + * @event onProgress + */ + +/** + * Fired when all the assets have loaded + * @event onComplete + */ + +// constructor +PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; + +/** + * Starts loading the assets sequentially + * + * @method load + */ +PIXI.AssetLoader.prototype.load = function() +{ + var scope = this; + + this.loadCount = this.assetURLs.length; + + for (var i=0; i < this.assetURLs.length; i++) + { + var fileName = this.assetURLs[i]; + var fileType = fileName.split("?").shift().split(".").pop().toLowerCase(); + + var loaderClass = this.loadersByType[fileType]; + if(!loaderClass) + throw new Error(fileType + " is an unsupported file type"); + + var loader = new loaderClass(fileName, this.crossorigin); + + loader.addEventListener("loaded", function() + { + scope.onAssetLoaded(); + }); + loader.load(); + } +}; + +/** + * Invoked after each file is loaded + * + * @method onAssetLoaded + * @private + */ +PIXI.AssetLoader.prototype.onAssetLoaded = function() +{ + this.loadCount--; + this.dispatchEvent({type: "onProgress", content: this}); + if(this.onProgress) this.onProgress(); + + if(this.loadCount == 0) + { + this.dispatchEvent({type: "onComplete", content: this}); + if(this.onComplete) this.onComplete(); + } +}; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The json file loader is used to load in JSON data and parsing it + * When loaded this class will dispatch a "loaded" event + * If load failed this class will dispatch a "error" event + * + * @class JsonLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.JsonLoader = function (url, crossorigin) { + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * [read-only] Whether the data has loaded yet + * + * @property loaded + * @type Boolean + * @readOnly + */ + this.loaded = false; + +}; + +// constructor +PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; + +/** + * Loads the JSON data + * + * @method load + */ +PIXI.JsonLoader.prototype.load = function () { + this.ajaxRequest = new AjaxRequest(); + var scope = this; + this.ajaxRequest.onreadystatechange = function () { + scope.onJSONLoaded(); + }; + + this.ajaxRequest.open("GET", this.url, true); + if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); + this.ajaxRequest.send(null); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.JsonLoader.prototype.onJSONLoaded = function () { + if (this.ajaxRequest.readyState == 4) { + if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { + this.json = JSON.parse(this.ajaxRequest.responseText); + + if(this.json.frames) + { + // sprite sheet + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); + + } + else if(this.json.bones) + { + // spine animation + var spineJsonParser = new spine.SkeletonJson(); + var skeletonData = spineJsonParser.readSkeletonData(this.json); + PIXI.AnimCache[this.url] = skeletonData; + this.onLoaded(); + } + else + { + this.onLoaded(); + } + } + else + { + this.onError(); + } + } +}; + +/** + * Invoke when json file loaded + * + * @method onLoaded + * @private + */ +PIXI.JsonLoader.prototype.onLoaded = function () { + this.loaded = true; + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * Invoke when error occured + * + * @method onError + * @private + */ +PIXI.JsonLoader.prototype.onError = function () { + this.dispatchEvent({ + type: "error", + content: this + }); +}; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The sprite sheet loader is used to load in JSON sprite sheet data + * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format + * There is a free version so thats nice, although the paid version is great value for money. + * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. + * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * This loader will also load the image file that the Spritesheet points to as well as the data. + * When loaded this class will dispatch a "loaded" event + * + * @class SpriteSheetLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the sprite sheet JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ + +PIXI.SpriteSheetLoader = function (url, crossorigin) { + /* + * i use texture packer to load the assets.. + * http://www.codeandweb.com/texturepacker + * make sure to set the format as "JSON" + */ + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = null; + + /** + * The frames of the sprite sheet + * + * @property frames + * @type Object + */ + this.frames = {}; +}; + +// constructor +PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; + +/** + * This will begin loading the JSON file + * + * @method load + */ +PIXI.SpriteSheetLoader.prototype.load = function () { + var scope = this; + var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); + jsonLoader.addEventListener("loaded", function (event) { + scope.json = event.content.json; + scope.onJSONLoaded(); + }); + jsonLoader.load(); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); +}; +/** + * Invoke when all files are loaded (json and texture) + * + * @method onLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onLoaded = function () { + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") + * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * When loaded this class will dispatch a 'loaded' event + * + * @class ImageLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the image + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.ImageLoader = function(url, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = PIXI.Texture.fromImage(url, crossorigin); + + /** + * if the image is loaded with loadFramedSpriteSheet + * frames will contain the sprite sheet frames + * + */ + this.frames = []; +}; + +// constructor +PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; + +/** + * Loads image or takes it from cache + * + * @method load + */ +PIXI.ImageLoader.prototype.load = function() +{ + if(!this.texture.baseTexture.hasLoaded) + { + var scope = this; + this.texture.baseTexture.addEventListener("loaded", function() + { + scope.onLoaded(); + }); + } + else + { + this.onLoaded(); + } +}; + +/** + * Invoked when image file is loaded or it is already cached and ready to use + * + * @method onLoaded + * @private + */ +PIXI.ImageLoader.prototype.onLoaded = function() +{ + this.dispatchEvent({type: "loaded", content: this}); +}; + +/** + * Loads image and split it to uniform sized frames + * + * + * @method loadFramedSpriteSheet + * @param frameWidth {Number} with of each frame + * @param frameHeight {Number} height of each frame + * @param textureName {String} if given, the frames will be cached in - format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y>16)/255,(255&a>>8)/255,(255&a)/255]}function d(a){return[(255&a>>16)/255,(255&a>>8)/255,(255&a)/255]}var e=this,f=f||{};f.Point=function(a,b){this.x=a||0,this.y=b||0},f.Point.prototype.clone=function(){return new f.Point(this.x,this.y)},f.Point.prototype.constructor=f.Point,f.Rectangle=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Rectangle.prototype.clone=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Rectangle.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=this.x;if(a>=c&&a<=c+this.width){var d=this.y;if(b>=d&&b<=d+this.height)return!0}return!1},f.Rectangle.prototype.constructor=f.Rectangle,f.Polygon=function(a){if(a instanceof Array||(a=Array.prototype.slice.call(arguments)),"number"==typeof a[0]){for(var b=[],c=0,d=a.length;d>c;c+=2)b.push(new f.Point(a[c],a[c+1]));a=b}this.points=a},f.Polygon.prototype.clone=function(){for(var a=[],b=0;bb!=i>b&&(h-f)*(b-g)/(i-g)+f>a;j&&(c=!c)}return c},f.Polygon.prototype.constructor=f.Polygon,f.Circle=function(a,b,c){this.x=a||0,this.y=b||0,this.radius=c||0},f.Circle.prototype.clone=function(){return new f.Circle(this.x,this.y,this.radius)},f.Circle.prototype.contains=function(a,b){if(this.radius<=0)return!1;var c=this.x-a,d=this.y-b,e=this.radius*this.radius;return c*=c,d*=d,e>=c+d},f.Circle.prototype.constructor=f.Circle,f.Ellipse=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Ellipse.prototype.clone=function(){return new f.Ellipse(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=(a-this.x)/this.width-.5,d=(b-this.y)/this.height-.5;return c*=c,d*=d,.25>c+d},f.Ellipse.getBounds=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.constructor=f.Ellipse,c(),f.mat3={},f.mat3.create=function(){var a=new f.Matrix(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat3.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat4={},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat3.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=m*d+n*g+o*j,c[1]=m*e+n*h+o*k,c[2]=m*f+n*i+o*l,c[3]=p*d+q*g+r*j,c[4]=p*e+q*h+r*k,c[5]=p*f+q*i+r*l,c[6]=s*d+t*g+u*j,c[7]=s*e+t*h+u*k,c[8]=s*f+t*i+u*l,c},f.mat3.clone=function(a){var b=new f.Matrix(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.mat3.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.mat3.toMat4=function(a,b){return b||(b=f.mat4.create()),b[15]=1,b[14]=0,b[13]=0,b[12]=0,b[11]=0,b[10]=a[8],b[9]=a[7],b[8]=a[6],b[7]=0,b[6]=a[5],b[5]=a[4],b[4]=a[3],b[3]=0,b[2]=a[2],b[1]=a[1],b[0]=a[0],b},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat4.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},f.mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,t=b[4],u=b[5],v=b[6],w=b[7],c[4]=t*d+u*h+v*l+w*p,c[5]=t*e+u*i+v*m+w*q,c[6]=t*f+u*j+v*n+w*r,c[7]=t*g+u*k+v*o+w*s,t=b[8],u=b[9],v=b[10],w=b[11],c[8]=t*d+u*h+v*l+w*p,c[9]=t*e+u*i+v*m+w*q,c[10]=t*f+u*j+v*n+w*r,c[11]=t*g+u*k+v*o+w*s,t=b[12],u=b[13],v=b[14],w=b[15],c[12]=t*d+u*h+v*l+w*p,c[13]=t*e+u*i+v*m+w*q,c[14]=t*f+u*j+v*n+w*r,c[15]=t*g+u*k+v*o+w*s,c},f.DisplayObject=function(){this.last=this,this.first=this,this.position=new f.Point,this.scale=new f.Point(1,1),this.pivot=new f.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.parent=null,this.stage=null,this.worldAlpha=1,this._interactive=!1,this.worldTransform=f.mat3.create(),this.localTransform=f.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1,this.filterArea=new f.Rectangle(0,0,1,1)},f.DisplayObject.prototype.constructor=f.DisplayObject,f.DisplayObject.prototype.setInteractive=function(a){this.interactive=a},Object.defineProperty(f.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(a){this._interactive=a,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(f.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(a){a?this._mask?(a.start=this._mask.start,a.end=this._mask.end):(this.addFilter(a),a.renderable=!1):(this.removeFilter(this._mask),this._mask.renderable=!0),this._mask=a}}),Object.defineProperty(f.DisplayObject.prototype,"filters",{get:function(){return this._filters},set:function(a){if(a){this._filters&&this.removeFilter(this._filters),this.addFilter(a);for(var b=[],c=0;c=0&&b<=this.children.length))throw new Error(a+" The index "+b+" supplied is out of bounds "+this.children.length);if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.stage){var c=a;do c.interactive&&(this.stage.dirty=!0),c.stage=this.stage,c=c._iNext;while(c)}var d,e,f=a.first,g=a.last;if(b==this.children.length){e=this.last;for(var h=this,i=this.last;h;)h.last==i&&(h.last=a.last),h=h.parent}else e=0==b?this:this.children[b-1].last;d=e._iNext,d&&(d._iPrev=g,g._iNext=d),f._iPrev=e,e._iNext=f,this.children.splice(b,0,a),this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.swapChildren=function(){},f.DisplayObjectContainer.prototype.getChildAt=function(a){if(a>=0&&aa;a++)this.children[a].updateTransform()}},f.blendModes={},f.blendModes.NORMAL=0,f.blendModes.SCREEN=1,f.Sprite=function(a){f.DisplayObjectContainer.call(this),this.anchor=new f.Point,this.texture=a,this.blendMode=f.blendModes.NORMAL,this._width=0,this._height=0,a.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Sprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Sprite.prototype.constructor=f.Sprite,Object.defineProperty(f.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(a){this.scale.x=a/this.texture.frame.width,this._width=a}}),Object.defineProperty(f.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(a){this.scale.y=a/this.texture.frame.height,this._height=a}}),f.Sprite.prototype.setTexture=function(a){this.texture.baseTexture!=a.baseTexture?(this.textureChange=!0,this.texture=a,this.__renderGroup&&this.__renderGroup.updateTexture(this)):this.texture=a,this.updateFrame=!0},f.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},f.Sprite.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache"+this);return new f.Sprite(b)},f.Sprite.fromImage=function(a){var b=f.Texture.fromImage(a);return new f.Sprite(b)},f.MovieClip=function(a){f.Sprite.call(this,a[0]),this.textures=a,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},f.MovieClip.prototype=Object.create(f.Sprite.prototype),f.MovieClip.prototype.constructor=f.MovieClip,Object.defineProperty(f.MovieClip.prototype,"totalFrames",{get:function(){return this.textures.length}}),f.MovieClip.prototype.stop=function(){this.playing=!1},f.MovieClip.prototype.play=function(){this.playing=!0},f.MovieClip.prototype.gotoAndStop=function(a){this.playing=!1,this.currentFrame=a;var b=0|this.currentFrame+.5;this.setTexture(this.textures[b%this.textures.length])},f.MovieClip.prototype.gotoAndPlay=function(a){this.currentFrame=a,this.playing=!0},f.MovieClip.prototype.updateTransform=function(){if(f.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var a=0|this.currentFrame+.5;this.loop||a=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},f.FilterBlock=function(){this.visible=!0,this.renderable=!0},f.Text=function(a,b){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),f.Sprite.call(this,f.Texture.fromCanvas(this.canvas)),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.Text.prototype=Object.create(f.Sprite.prototype),f.Text.prototype.constructor=f.Text,f.Text.prototype.setStyle=function(a){a=a||{},a.font=a.font||"bold 20pt Arial",a.fill=a.fill||"black",a.align=a.align||"left",a.stroke=a.stroke||"black",a.strokeThickness=a.strokeThickness||0,a.wordWrap=a.wordWrap||!1,a.wordWrapWidth=a.wordWrapWidth||100,this.style=a,this.dirty=!0},f.Text.prototype.setText=function(a){this.text=a.toString()||" ",this.dirty=!0},f.Text.prototype.updateText=function(){this.context.font=this.style.font;var a=this.text;this.style.wordWrap&&(a=this.wordWrap(this.text));for(var b=a.split(/(?:\r\n|\r|\n)/),c=[],d=0,e=0;ee?(g>0&&(b+="\n"),b+=f[g]+" ",e=this.style.wordWrapWidth-h):(e-=i,b+=f[g]+" ")}b+="\n"}return b},f.Text.prototype.destroy=function(a){a&&this.texture.destroy()},f.Text.heightCache={},f.BitmapText=function(a,b){f.DisplayObjectContainer.call(this),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.BitmapText.prototype=Object.create(f.DisplayObjectContainer.prototype),f.BitmapText.prototype.constructor=f.BitmapText,f.BitmapText.prototype.setText=function(a){this.text=a||" ",this.dirty=!0},f.BitmapText.prototype.setStyle=function(a){a=a||{},a.align=a.align||"left",this.style=a;var b=a.font.split(" ");this.fontName=b[b.length-1],this.fontSize=b.length>=2?parseInt(b[b.length-2],10):f.BitmapText.fonts[this.fontName].size,this.dirty=!0},f.BitmapText.prototype.updateText=function(){for(var a=f.BitmapText.fonts[this.fontName],b=new f.Point,c=null,d=[],e=0,g=[],h=0,i=this.fontSize/a.size,j=0;j=j;j++){var n=0;"right"==this.style.align?n=e-g[j]:"center"==this.style.align&&(n=(e-g[j])/2),m.push(n)}for(j=0;j0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.BitmapText.fonts={},f.InteractionManager=function(a){this.stage=a,this.mouse=new f.InteractionData,this.touchs={},this.tempPoint=new f.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0},f.InteractionManager.prototype.constructor=f.InteractionManager,f.InteractionManager.prototype.collectInteractiveSprite=function(a,b){for(var c=a.children,d=c.length,e=d-1;e>=0;e--){var f=c[e];f.interactive?(b.interactiveChildren=!0,this.interactiveItems.push(f),f.children.length>0&&this.collectInteractiveSprite(f,f)):(f.__iParent=null,f.children.length>0&&this.collectInteractiveSprite(f,b))}},f.InteractionManager.prototype.setTarget=function(a){this.target=a,null===this.interactionDOMElement&&this.setTargetDomElement(a.view),document.body.addEventListener("mouseup",this.onMouseUp,!0)},f.InteractionManager.prototype.setTargetDomElement=function(a){null!==this.interactionDOMElement&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]="",this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0)),window.navigator.msPointerEnabled&&(a.style["-ms-content-zooming"]="none",a.style["-ms-touch-action"]="none"),this.interactionDOMElement=a,a.addEventListener("mousemove",this.onMouseMove,!0),a.addEventListener("mousedown",this.onMouseDown,!0),a.addEventListener("mouseout",this.onMouseOut,!0),a.addEventListener("touchstart",this.onTouchStart,!0),a.addEventListener("touchend",this.onTouchEnd,!0),a.addEventListener("touchmove",this.onTouchMove,!0)},f.InteractionManager.prototype.update=function(){if(this.target){var a=Date.now(),b=a-this.last;if(b=30*b/1e3,!(1>b)){if(this.last=a,this.dirty){this.dirty=!1;for(var c=this.interactiveItems.length,d=0;c>d;d++)this.interactiveItems[d].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var e=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var d=0;e>d;d++){var f=this.interactiveItems[d];(f.mouseover||f.mouseout||f.buttonMode)&&(f.__hit=this.hitTest(f,this.mouse),this.mouse.target=f,f.__hit?(f.buttonMode&&(this.interactionDOMElement.style.cursor="pointer"),f.__isOver||(f.mouseover&&f.mouseover(this.mouse),f.__isOver=!0)):f.__isOver&&(f.mouseout&&f.mouseout(this.mouse),f.__isOver=!1))}}}},f.InteractionManager.prototype.onMouseMove=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(a.clientX-b.left)*(this.target.width/b.width),this.mouse.global.y=(a.clientY-b.top)*(this.target.height/b.height);var c=this.interactiveItems.length;this.mouse.global;for(var d=0;c>d;d++){var e=this.interactiveItems[d];e.mousemove&&e.mousemove(this.mouse)}},f.InteractionManager.prototype.onMouseDown=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactiveItems.length;this.mouse.global,this.stage;for(var c=0;b>c;c++){var d=this.interactiveItems[c];if((d.mousedown||d.click)&&(d.__mouseIsDown=!0,d.__hit=this.hitTest(d,this.mouse),d.__hit&&(d.mousedown&&d.mousedown(this.mouse),d.__isDown=!0,!d.interactiveChildren)))break}},f.InteractionManager.prototype.onMouseOut=function(){var a=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var b=0;a>b;b++){var c=this.interactiveItems[b];c.__isOver&&(this.mouse.target=c,c.mouseout&&c.mouseout(this.mouse),c.__isOver=!1)}},f.InteractionManager.prototype.onMouseUp=function(a){this.mouse.originalEvent=a||window.event,this.mouse.global;for(var b=this.interactiveItems.length,c=!1,d=0;b>d;d++){var e=this.interactiveItems[d];(e.mouseup||e.mouseupoutside||e.click)&&(e.__hit=this.hitTest(e,this.mouse),e.__hit&&!c?(e.mouseup&&e.mouseup(this.mouse),e.__isDown&&e.click&&e.click(this.mouse),e.interactiveChildren||(c=!0)):e.__isDown&&e.mouseupoutside&&e.mouseupoutside(this.mouse),e.__isDown=!1)}},f.InteractionManager.prototype.hitTest=function(a,b){var c=b.global;if(a.vcount!==f.visibleCount)return!1;var d=a instanceof f.Sprite,e=a.worldTransform,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=1/(g*k+h*-j),n=k*m*c.x+-h*m*c.y+(l*h-i*k)*m,o=g*m*c.y+-j*m*c.x+(-l*g+i*j)*m;if(b.target=a,a.hitArea&&a.hitArea.contains)return a.hitArea.contains(n,o)?(b.target=a,!0):!1;if(d){var p,q=a.texture.frame.width,r=a.texture.frame.height,s=-q*a.anchor.x;if(n>s&&s+q>n&&(p=-r*a.anchor.y,o>p&&p+r>o))return b.target=a,!0}for(var t=a.children.length,u=0;t>u;u++){var v=a.children[u],w=this.hitTest(v,b);if(w)return b.target=a,!0}return!1},f.InteractionManager.prototype.onTouchMove=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;dd;d++){var h=this.interactiveItems[d];h.touchmove&&h.touchmove(f)}},f.InteractionManager.prototype.onTouchStart=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i];if((j.touchstart||j.tap)&&(j.__hit=this.hitTest(j,g),j.__hit&&(j.touchstart&&j.touchstart(g),j.__isDown=!0,j.__touchData=g,!j.interactiveChildren)))break}}},f.InteractionManager.prototype.onTouchEnd=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i],k=j.__touchData;j.__hit=this.hitTest(j,f),k==f&&(f.originalEvent=a||window.event,(j.touchend||j.tap)&&(j.__hit&&!g?(j.touchend&&j.touchend(f),j.__isDown&&j.tap&&j.tap(f),j.interactiveChildren||(g=!0)):j.__isDown&&j.touchendoutside&&j.touchendoutside(f),j.__isDown=!1),j.__touchData=null)}this.pool.push(f),this.touchs[e.identifier]=null}},f.InteractionData=function(){this.global=new f.Point,this.local=new f.Point,this.target,this.originalEvent},f.InteractionData.prototype.getLocalPosition=function(a){var b=a.worldTransform,c=this.global,d=b[0],e=b[1],g=b[2],h=b[3],i=b[4],j=b[5],k=1/(d*i+e*-h);return new f.Point(i*k*c.x+-e*k*c.y+(j*e-g*i)*k,d*k*c.y+-h*k*c.x+(-j*d+g*h)*k)},f.InteractionData.prototype.constructor=f.InteractionData,f.Stage=function(a){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=!0,this.interactionManager=new f.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new f.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(a),this.worldVisible=!0},f.Stage.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Stage.prototype.constructor=f.Stage,f.Stage.prototype.setInteractionDelegate=function(a){this.interactionManager.setTargetDomElement(a)},f.Stage.prototype.updateTransform=function(){this.worldAlpha=1,this.vcount=f.visibleCount;for(var a=0,b=this.children.length;b>a;a++)this.children[a].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},f.Stage.prototype.setBackgroundColor=function(a){this.backgroundColor=a||0,this.backgroundColorSplit=d(this.backgroundColor);var b=this.backgroundColor.toString(16);b="000000".substr(0,6-b.length)+b,this.backgroundColorString="#"+b},f.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var h=0,i=["ms","moz","webkit","o"],j=0;j>>>>>>>>"),console.log("_");var b=0,c=a.first;for(console.log(c);c._iNext;)if(b++,c=c._iNext,console.log(c),b>100){console.log("BREAK");break}},f.EventTarget=function(){var a={};this.addEventListener=this.on=function(b,c){void 0===a[b]&&(a[b]=[]),-1===a[b].indexOf(c)&&a[b].push(c)},this.dispatchEvent=this.emit=function(b){if(a[b.type]&&a[b.type].length)for(var c=0,d=a[b.type].length;d>c;c++)a[b.type][c](b)},this.removeEventListener=this.off=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}},f.autoDetectRenderer=function(a,b,c,d,e){a||(a=800),b||(b=600);var g=function(){try{var a=document.createElement("canvas");return!!window.WebGLRenderingContext&&(a.getContext("webgl")||a.getContext("experimental-webgl"))}catch(b){return!1}}();if(g){var h=-1!=navigator.userAgent.toLowerCase().indexOf("msie");g=!h}return g?new f.WebGLRenderer(a,b,c,d,e):new f.CanvasRenderer(a,b,c,d)},f.PolyK={},f.PolyK.Triangulate=function(a){var b=!0,c=a.length>>1;if(3>c)return[];for(var d=[],e=[],g=0;c>g;g++)e.push(g);for(var g=0,h=c;h>3;){var i=e[(g+0)%h],j=e[(g+1)%h],k=e[(g+2)%h],l=a[2*i],m=a[2*i+1],n=a[2*j],o=a[2*j+1],p=a[2*k],q=a[2*k+1],r=!1;if(f.PolyK._convex(l,m,n,o,p,q,b)){r=!0;for(var s=0;h>s;s++){var t=e[s];if(t!=i&&t!=j&&t!=k&&f.PolyK._PointInTriangle(a[2*t],a[2*t+1],l,m,n,o,p,q)){r=!1;break}}}if(r)d.push(i,j,k),e.splice((g+1)%h,1),h--,g=0;else if(g++>3*h){if(!b)return console.log("PIXI Warning: shape too complex to fill"),[];var d=[];e=[];for(var g=0;c>g;g++)e.push(g);g=0,h=c,b=!1}}return d.push(e[0],e[1],e[2]),d},f.PolyK._PointInTriangle=function(a,b,c,d,e,f,g,h){var i=g-c,j=h-d,k=e-c,l=f-d,m=a-c,n=b-d,o=i*i+j*j,p=i*k+j*l,q=i*m+j*n,r=k*k+l*l,s=k*m+l*n,t=1/(o*r-p*p),u=(r*q-p*s)*t,v=(o*s-p*q)*t;return u>=0&&v>=0&&1>u+v},f.PolyK._convex=function(a,b,c,d,e,f,g){return(b-d)*(e-c)+(c-a)*(f-d)>=0==g},f.initDefaultShaders=function(){f.primitiveShader=new f.PrimitiveShader,f.primitiveShader.init(),f.stripShader=new f.StripShader,f.stripShader.init(),f.defaultShader=new f.PixiShader,f.defaultShader.init();var a=f.gl,b=f.defaultShader.program;a.useProgram(b),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.primitiveShader.program),a.disableVertexAttribArray(f.defaultShader.aVertexPosition),a.disableVertexAttribArray(f.defaultShader.colorAttribute),a.disableVertexAttribArray(f.defaultShader.aTextureCoord),a.enableVertexAttribArray(f.primitiveShader.aVertexPosition),a.enableVertexAttribArray(f.primitiveShader.colorAttribute)},f.deactivatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program),a.disableVertexAttribArray(f.primitiveShader.aVertexPosition),a.disableVertexAttribArray(f.primitiveShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activateStripShader=function(){var a=f.gl;a.useProgram(f.stripShader.program)},f.deactivateStripShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program)},f.CompileVertexShader=function(a,b){return f._CompileShader(a,b,a.VERTEX_SHADER)},f.CompileFragmentShader=function(a,b){return f._CompileShader(a,b,a.FRAGMENT_SHADER)},f._CompileShader=function(a,b,c){var d=b.join("\n"),e=a.createShader(c);return a.shaderSource(e,d),a.compileShader(e),a.getShaderParameter(e,a.COMPILE_STATUS)?e:(console.log(a.getShaderInfoLog(e)),null)},f.compileProgram=function(a,b){var c=f.gl,d=f.CompileFragmentShader(c,b),e=f.CompileVertexShader(c,a),g=c.createProgram();return c.attachShader(g,e),c.attachShader(g,d),c.linkProgram(g),c.getProgramParameter(g,c.LINK_STATUS)||console.log("Could not initialise shaders"),g},f.PixiShader=function(){this.program,this.fragmentSrc=["precision lowp float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;","}"]},f.PixiShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc||f.PixiShader.defaultVertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"); -for(var c in this.uniforms)this.uniforms[c].uniformLocation=b.getUniformLocation(a,c);this.program=a},f.PixiShader.prototype.syncUniforms=function(){var a=f.gl;for(var b in this.uniforms){var c=this.uniforms[b].type;if("f"==c&&a.uniform1f(this.uniforms[b].uniformLocation,this.uniforms[b].value),"f2"==c)a.uniform2f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("f4"==c)a.uniform4fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("mat4"==c)a.uniformMatrix4fv(this.uniforms[b].uniformLocation,!1,this.uniforms[b].value);else if("sampler2D"==c){var d=this.uniforms[b].value;a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,d.baseTexture._glTexture),a.uniform1i(this.uniforms[b].uniformLocation,1)}}},f.PixiShader.defaultVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","varying vec2 vTextureCoord;","varying float vColor;","const vec2 center = vec2(-1.0, 1.0);","void main(void) {","gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.StripShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying vec2 offsetVector;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"]},f.StripShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.PrimitiveShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"]},f.PrimitiveShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.WebGLGraphics=function(){},f.WebGLGraphics.renderGraphics=function(a,b){var c=f.gl;a._webGL||(a._webGL={points:[],indices:[],lastIndex:0,buffer:c.createBuffer(),indexBuffer:c.createBuffer()}),a.dirty&&(a.dirty=!1,a.clearDirty&&(a.clearDirty=!1,a._webGL.lastIndex=0,a._webGL.points=[],a._webGL.indices=[]),f.WebGLGraphics.updateGraphics(a)),f.activatePrimitiveShader();var d=f.mat3.clone(a.worldTransform);f.mat3.transpose(d),c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA),c.uniformMatrix3fv(f.primitiveShader.translationMatrix,!1,d),c.uniform2f(f.primitiveShader.projectionVector,b.x,-b.y),c.uniform2f(f.primitiveShader.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(f.primitiveShader.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.primitiveShader.aVertexPosition,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveShader.colorAttribute,4,c.FLOAT,!1,24,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),c.drawElements(c.TRIANGLE_STRIP,a._webGL.indices.length,c.UNSIGNED_SHORT,0),f.deactivatePrimitiveShader()},f.WebGLGraphics.updateGraphics=function(a){for(var b=a._webGL.lastIndex;b3&&f.WebGLGraphics.buildPoly(c,a._webGL),c.lineWidth>0&&f.WebGLGraphics.buildLine(c,a._webGL)):c.type==f.Graphics.RECT?f.WebGLGraphics.buildRectangle(c,a._webGL):(c.type==f.Graphics.CIRC||c.type==f.Graphics.ELIP)&&f.WebGLGraphics.buildCircle(c,a._webGL)}a._webGL.lastIndex=a.graphicsData.length;var d=f.gl;a._webGL.glPoints=new Float32Array(a._webGL.points),d.bindBuffer(d.ARRAY_BUFFER,a._webGL.buffer),d.bufferData(d.ARRAY_BUFFER,a._webGL.glPoints,d.STATIC_DRAW),a._webGL.glIndicies=new Uint16Array(a._webGL.indices),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),d.bufferData(d.ELEMENT_ARRAY_BUFFER,a._webGL.glIndicies,d.STATIC_DRAW)},f.WebGLGraphics.buildRectangle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3];if(a.fill){var j=d(a.fillColor),k=a.fillAlpha,l=j[0]*k,m=j[1]*k,n=j[2]*k,o=b.points,p=b.indices,q=o.length/6;o.push(e,g),o.push(l,m,n,k),o.push(e+h,g),o.push(l,m,n,k),o.push(e,g+i),o.push(l,m,n,k),o.push(e+h,g+i),o.push(l,m,n,k),p.push(q,q,q+1,q+2,q+3,q+3)}a.lineWidth&&(a.points=[e,g,e+h,g,e+h,g+i,e,g+i,e,g],f.WebGLGraphics.buildLine(a,b))},f.WebGLGraphics.buildCircle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3],j=40,k=2*Math.PI/j;if(a.fill){var l=d(a.fillColor),m=a.fillAlpha,n=l[0]*m,o=l[1]*m,p=l[2]*m,q=b.points,r=b.indices,s=q.length/6;r.push(s);for(var t=0;j+1>t;t++)q.push(e,g,n,o,p,m),q.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i,n,o,p,m),r.push(s++,s++);r.push(s-1)}if(a.lineWidth){a.points=[];for(var t=0;j+1>t;t++)a.points.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i);f.WebGLGraphics.buildLine(a,b)}},f.WebGLGraphics.buildLine=function(a,b){var c=a.points;if(0!=c.length){if(a.lineWidth%2)for(var e=0;ee;e++)k=c[2*(e-1)],l=c[2*(e-1)+1],m=c[2*e],n=c[2*e+1],o=c[2*(e+1)],p=c[2*(e+1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,s=-(n-p),t=m-o,E=Math.sqrt(s*s+t*t),s/=E,t/=E,s*=K,t*=K,w=-r+l-(-r+n),x=-q+m-(-q+k),y=(-q+k)*(-r+n)-(-q+m)*(-r+l),z=-t+p-(-t+n),A=-s+m-(-s+o),B=(-s+o)*(-t+n)-(-s+m)*(-t+p),C=w*A-z*x,Math.abs(C)<.1?(C+=10.1,F.push(m-q,n-r,N,O,P,M),F.push(m+q,n+r,N,O,P,M)):(px=(x*B-A*y)/C,py=(z*y-w*B)/C,D=(px-m)*(px-m)+(py-n)+(py-n),D>19600?(u=q-s,v=r-t,E=Math.sqrt(u*u+v*v),u/=E,v/=E,u*=K,v*=K,F.push(m-u,n-v),F.push(N,O,P,M),F.push(m+u,n+v),F.push(N,O,P,M),F.push(m-u,n-v),F.push(N,O,P,M),I++):(F.push(px,py),F.push(N,O,P,M),F.push(m-(px-m),n-(py-n)),F.push(N,O,P,M)));k=c[2*(H-2)],l=c[2*(H-2)+1],m=c[2*(H-1)],n=c[2*(H-1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,F.push(m-q,n-r),F.push(N,O,P,M),F.push(m+q,n+r),F.push(N,O,P,M),G.push(J);for(var e=0;I>e;e++)G.push(J++);G.push(J-1)}},f.WebGLGraphics.buildPoly=function(a,b){var c=a.points;if(!(c.length<6)){for(var e=b.points,g=b.indices,h=c.length/2,i=d(a.fillColor),j=a.fillAlpha,k=i[0]*j,l=i[1]*j,m=i[2]*j,n=f.PolyK.Triangulate(c),o=e.length/6,p=0;pp;p++)e.push(c[2*p],c[2*p+1],k,l,m,j)}},f._defaultFrame=new f.Rectangle(0,0,1,1),f.gl,f.WebGLRenderer=function(a,b,c,d,e){this.transparent=!!d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var g=this;this.view.addEventListener("webglcontextlost",function(a){g.handleContextLost(a)},!1),this.view.addEventListener("webglcontextrestored",function(a){g.handleContextRestored(a)},!1),this.batchs=[];var h={alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0};try{f.gl=this.gl=this.view.getContext("experimental-webgl",h)}catch(i){try{f.gl=this.gl=this.view.getContext("webgl",h)}catch(i){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}}f.initDefaultShaders();var j=this.gl;j.useProgram(f.defaultShader.program),f.WebGLRenderer.gl=j,this.batch=new f.WebGLBatch(j),j.disable(j.DEPTH_TEST),j.disable(j.CULL_FACE),j.enable(j.BLEND),j.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),f.offset=new f.Point(0,0),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new f.WebGLRenderGroup(this.gl,this.transparent)},f.WebGLRenderer.prototype.constructor=f.WebGLRenderer,f.WebGLRenderer.getBatch=function(){return 0==f._batchs.length?new f.WebGLBatch(f.WebGLRenderer.gl):f._batchs.pop()},f.WebGLRenderer.returnBatch=function(a){a.clean(),f._batchs.push(a)},f.WebGLRenderer.prototype.render=function(a){if(!this.contextLost){this.__stage!==a&&(this.__stage=a,this.stageRenderGroup.setRenderable(a)),f.WebGLRenderer.updateTextures(),f.visibleCount++,a.updateTransform();var b=this.gl;if(b.colorMask(!0,!0,!0,this.transparent),b.viewport(0,0,this.width,this.height),b.bindFramebuffer(b.FRAMEBUFFER,null),b.clearColor(a.backgroundColorSplit[0],a.backgroundColorSplit[1],a.backgroundColorSplit[2],!this.transparent),b.clear(b.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=a.backgroundColorSplit,f.projection.x=this.width/2,f.projection.y=-this.height/2,this.stageRenderGroup.render(f.projection),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0){for(var c=0;cc;c++){var d=6*c,e=4*c;this.indices[d+0]=e+0,this.indices[d+1]=e+1,this.indices[d+2]=e+2,this.indices[d+3]=e+0,this.indices[d+4]=e+2,this.indices[d+5]=e+3}a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,this.indices,a.STATIC_DRAW)},f.WebGLBatch.prototype.refresh=function(){this.gl,this.dynamicSizen;n++)renderable=this.batchs[n],renderable instanceof f.WebGLBatch?this.batchs[n].render():this.renderSpecial(renderable,b);endBatch instanceof f.WebGLBatch?endBatch.render(0,h+1):this.renderSpecial(endBatch,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){var c=a.vcount===f.visibleCount;a instanceof f.TilingSprite?c&&this.renderTilingSprite(a,b):a instanceof f.Strip?c&&this.renderStrip(a,b):a instanceof f.CustomRenderable?c&&a.renderWebGL(this,b):a instanceof f.Graphics?c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b):a instanceof f.FilterBlock&&this.handleFilterBlock(a,b)},flip=!1;var l=[],m=0;f.WebGLRenderGroup.prototype.handleFilterBlock=function(a,b){var c=f.gl;if(a.open)a.data instanceof Array?this.filterManager.pushFilter(a):(m++,l.push(a),c.enable(c.STENCIL_TEST),c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.INCR),f.WebGLGraphics.renderGraphics(a.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP));else if(a.data instanceof Array)this.filterManager.popFilter();else{var d=l.pop(a);d&&(c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.DECR),f.WebGLGraphics.renderGraphics(d.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP)),c.disable(c.STENCIL_TEST)}},f.WebGLRenderGroup.prototype.updateTexture=function(a){this.removeObject(a);for(var b=a.first;b!=this.root&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););this.insertObject(a,b,c)},f.WebGLRenderGroup.prototype.addFilterBlocks=function(a,b){a.__renderGroup=this,b.__renderGroup=this;for(var c=a;c!=this.root.first&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root.first&&(d=d._iPrev,!d.renderable||!d.__renderGroup););this.insertAfter(b,d)},f.WebGLRenderGroup.prototype.removeFilterBlocks=function(a,b){this.removeObject(a),this.removeObject(b)},f.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(a){a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a);for(var b=a.first;b!=this.root.first&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););var d=a.first,e=a.last._iNext;do d.__renderGroup=this,d.renderable&&(this.insertObject(d,b,c),b=d),d=d._iNext;while(d!=e)},f.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(a){if(a.__renderGroup==this){a.last;do a.__renderGroup=null,a.renderable&&this.removeObject(a),a=a._iNext;while(a)}},f.WebGLRenderGroup.prototype.insertObject=function(a,b,c){var d=b,e=c;if(a instanceof f.Sprite){var g,h;if(d instanceof f.Sprite){if(g=d.batch,g&&g.texture==a.texture.baseTexture&&g.blendMode==a.blendMode)return g.insertAfter(a,d),void 0}else g=d;if(e)if(e instanceof f.Sprite){if(h=e.batch){if(h.texture==a.texture.baseTexture&&h.blendMode==a.blendMode)return h.insertBefore(a,e),void 0;if(h==g){var i=g.split(e),j=f.WebGLRenderer.getBatch(),k=this.batchs.indexOf(g);return j.init(a),this.batchs.splice(k+1,0,j,i),void 0}}}else h=e;var j=f.WebGLRenderer.getBatch();if(j.init(a),g){var k=this.batchs.indexOf(g);this.batchs.splice(k+1,0,j)}else this.batchs.push(j)}else a instanceof f.TilingSprite?this.initTilingSprite(a):a instanceof f.Strip&&this.initStrip(a),this.insertAfter(a,d)},f.WebGLRenderGroup.prototype.insertAfter=function(a,b){if(b instanceof f.Sprite){var c=b.batch;if(c)if(c.tail==b){var d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a)}else{var e=c.split(b.__next),d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a,e)}else this.batchs.push(a)}else{var d=this.batchs.indexOf(b);this.batchs.splice(d+1,0,a)}},f.WebGLRenderGroup.prototype.removeObject=function(a){var b;if(a instanceof f.Sprite){var c=a.batch;if(!c)return;c.remove(a),0==c.size&&(b=c)}else b=a;if(b){var d=this.batchs.indexOf(b);if(-1==d)return;if(0==d||d==this.batchs.length-1)return this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),void 0;if(this.batchs[d-1]instanceof f.WebGLBatch&&this.batchs[d+1]instanceof f.WebGLBatch&&this.batchs[d-1].texture==this.batchs[d+1].texture&&this.batchs[d-1].blendMode==this.batchs[d+1].blendMode)return this.batchs[d-1].merge(this.batchs[d+1]),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),f.WebGLRenderer.returnBatch(this.batchs[d+1]),this.batchs.splice(d,2),void 0;this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b)}},f.WebGLRenderGroup.prototype.initTilingSprite=function(a){var b=this.gl;a.verticies=new Float32Array([0,0,a.width,0,a.width,a.height,0,a.height]),a.uvs=new Float32Array([0,0,1,0,1,1,0,1]),a.colors=new Float32Array([1,1,1,1]),a.indices=new Uint16Array([0,1,3,2]),a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW),a.texture.baseTexture._glTexture?(b.bindTexture(b.TEXTURE_2D,a.texture.baseTexture._glTexture),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.REPEAT),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.REPEAT),a.texture.baseTexture._powerOf2=!0):a.texture.baseTexture._powerOf2=!0},f.WebGLRenderGroup.prototype.renderStrip=function(a,b){var c=this.gl;f.activateStripShader();var d=f.stripShader;d.program;var e=f.mat3.clone(a.worldTransform);f.mat3.transpose(e),c.uniformMatrix3fv(d.translationMatrix,!1,e),c.uniform2f(d.projectionVector,b.x,b.y),c.uniform2f(d.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(d.alpha,a.worldAlpha),a.dirty?(a.dirty=!1,c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferData(c.ARRAY_BUFFER,a.verticies,c.STATIC_DRAW),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferData(c.ARRAY_BUFFER,a.uvs,c.STATIC_DRAW),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.bufferData(c.ARRAY_BUFFER,a.colors,c.STATIC_DRAW),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,a.indices,c.STATIC_DRAW)):(c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.verticies),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer)),c.drawElements(c.TRIANGLE_STRIP,a.indices.length,c.UNSIGNED_SHORT,0),f.deactivateStripShader()},f.WebGLRenderGroup.prototype.renderTilingSprite=function(a,b){var c=this.gl;f.shaderProgram;var d=a.tilePosition,e=a.tileScale,g=d.x/a.texture.baseTexture.width,h=d.y/a.texture.baseTexture.height,i=a.width/a.texture.baseTexture.width/e.x,j=a.height/a.texture.baseTexture.height/e.y;a.uvs[0]=0-g,a.uvs[1]=0-h,a.uvs[2]=1*i-g,a.uvs[3]=0-h,a.uvs[4]=1*i-g,a.uvs[5]=1*j-h,a.uvs[6]=0-g,a.uvs[7]=1*j-h,c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.uvs),this.renderStrip(a,b)},f.WebGLRenderGroup.prototype.initStrip=function(a){var b=this.gl;this.shaderProgram,a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW)},f.WebGLFilterManager=function(a){this.transparent=a,this.filterStack=[],this.texturePool=[],this.offsetX=0,this.offsetY=0,this.initShaderBuffers()},f.WebGLFilterManager.prototype.begin=function(a,b){this.width=2*a.x,this.height=2*-a.y,this.buffer=b},f.WebGLFilterManager.prototype.pushFilter=function(a){var b=f.gl;this.filterStack.push(a);var c=a.filterPasses[0];this.offsetX+=a.target.filterArea.x,this.offsetY+=a.target.filterArea.y;var d=this.texturePool.pop();d||(d=new f.FilterTexture(this.width,this.height)),b.bindTexture(b.TEXTURE_2D,d.texture),this.getBounds(a.target);var e=a.target.filterArea,g=c.padding;e.x-=g,e.y-=g,e.width+=2*g,e.height+=2*g,e.x<0&&(e.x=0),e.width>this.width&&(e.width=this.width),e.y<0&&(e.y=0),e.height>this.height&&(e.height=this.height),b.bindFramebuffer(b.FRAMEBUFFER,d.frameBuffer),b.viewport(0,0,e.width,e.height),f.projection.x=e.width/2,f.projection.y=-e.height/2,f.offset.x=-e.x,f.offset.y=-e.y,b.uniform2f(f.defaultShader.projectionVector,e.width/2,-e.height/2),b.uniform2f(f.defaultShader.offsetVector,-e.x,-e.y),b.colorMask(!0,!0,!0,!0),b.clearColor(0,0,0,0),b.clear(b.COLOR_BUFFER_BIT),a._glFilterTexture=d},f.WebGLFilterManager.prototype.popFilter=function(){var a=f.gl,b=this.filterStack.pop(),c=b.target.filterArea,d=b._glFilterTexture;if(b.filterPasses.length>1){a.viewport(0,0,c.width,c.height),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer),this.vertexArray[0]=0,this.vertexArray[1]=c.height,this.vertexArray[2]=c.width,this.vertexArray[3]=c.height,this.vertexArray[4]=0,this.vertexArray[5]=0,this.vertexArray[6]=c.width,this.vertexArray[7]=0,a.bufferSubData(a.ARRAY_BUFFER,0,this.vertexArray),a.bindBuffer(a.ARRAY_BUFFER,this.uvBuffer),this.uvArray[2]=c.width/this.width,this.uvArray[5]=c.height/this.height,this.uvArray[6]=c.width/this.width,this.uvArray[7]=c.height/this.height,a.bufferSubData(a.ARRAY_BUFFER,0,this.uvArray);var e=d,g=this.texturePool.pop();g||(g=new f.FilterTexture(this.width,this.height)),a.bindFramebuffer(a.FRAMEBUFFER,g.frameBuffer),a.clear(a.COLOR_BUFFER_BIT),a.disable(a.BLEND);for(var h=0;hs?s:E,E=E>t?t:E,E=E>u?u:E,E=E>v?v:E,F=F>w?w:F,F=F>x?x:F,F=F>y?y:F,F=F>z?z:F,C=s>C?s:C,C=t>C?t:C,C=u>C?u:C,C=v>C?v:C,D=w>D?w:D,D=x>D?x:D,D=y>D?y:D,D=z>D?z:D),l=!1,A=A._iNext}while(A!=B);a.filterArea.x=E,a.filterArea.y=F,a.filterArea.width=C-E,a.filterArea.height=D-F},f.FilterTexture=function(a,b){var c=f.gl;this.frameBuffer=c.createFramebuffer(),this.texture=c.createTexture(),c.bindTexture(c.TEXTURE_2D,this.texture),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.bindFramebuffer(c.FRAMEBUFFER,this.framebuffer),c.bindFramebuffer(c.FRAMEBUFFER,this.frameBuffer),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,this.texture,0),this.resize(a,b)},f.FilterTexture.prototype.resize=function(a,b){this.width=a,this.height=b;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.texture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,a,b,0,c.RGBA,c.UNSIGNED_BYTE,null)},f.CanvasRenderer=function(a,b,c,d){this.transparent=d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},f.CanvasRenderer.prototype.constructor=f.CanvasRenderer,f.CanvasRenderer.prototype.render=function(a){f.texturesToUpdate=[],f.texturesToDestroy=[],f.visibleCount++,a.updateTransform(),this.view.style.backgroundColor==a.backgroundColorString||this.transparent||(this.view.style.backgroundColor=a.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(a),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0&&(f.Texture.frameUpdates=[])},f.CanvasRenderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.view.width=a,this.view.height=b},f.CanvasRenderer.prototype.renderDisplayObject=function(a){var b,c=this.context;c.globalCompositeOperation="source-over";var d=a.last._iNext;a=a.first;do if(b=a.worldTransform,a.visible)if(a.renderable){if(a instanceof f.Sprite){var e=a.texture.frame;e&&e.width&&e.height&&(c.globalAlpha=a.worldAlpha,c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),c.drawImage(a.texture.baseTexture.source,e.x,e.y,e.width,e.height,a.anchor.x*-e.width,a.anchor.y*-e.height,e.width,e.height))}else if(a instanceof f.Strip)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderStrip(a);else if(a instanceof f.TilingSprite)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderTilingSprite(a);else if(a instanceof f.CustomRenderable)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),a.renderCanvas(this);else if(a instanceof f.Graphics)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),f.CanvasGraphics.renderGraphics(a,c);else if(a instanceof f.FilterBlock&&a.data instanceof f.Graphics){var g=a.data;if(a.open){c.save();var h=g.alpha,i=g.worldTransform;c.setTransform(i[0],i[3],i[1],i[4],i[2],i[5]),g.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(g,c),c.clip(),g.worldAlpha=h}else c.restore()}a=a._iNext}else a=a._iNext;else a=a.last._iNext;while(a!=d)},f.CanvasRenderer.prototype.renderStripFlat=function(a){var b=this.context,c=a.verticies;a.uvs;var d=c.length/2;this.count++,b.beginPath();for(var e=1;d-2>e;e++){var f=2*e,g=c[f],h=c[f+2],i=c[f+4],j=c[f+1],k=c[f+3],l=c[f+5];b.moveTo(g,j),b.lineTo(h,k),b.lineTo(i,l)}b.fillStyle="#FF0000",b.fill(),b.closePath()},f.CanvasRenderer.prototype.renderTilingSprite=function(a){var b=this.context;b.globalAlpha=a.worldAlpha,a.__tilePattern||(a.__tilePattern=b.createPattern(a.texture.baseTexture.source,"repeat")),b.beginPath();var c=a.tilePosition,d=a.tileScale;b.scale(d.x,d.y),b.translate(c.x,c.y),b.fillStyle=a.__tilePattern,b.fillRect(-c.x,-c.y,a.width/d.x,a.height/d.y),b.scale(1/d.x,1/d.y),b.translate(-c.x,-c.y),b.closePath()},f.CanvasRenderer.prototype.renderStrip=function(a){var b=this.context,c=a.verticies,d=a.uvs,e=c.length/2;this.count++;for(var f=1;e-2>f;f++){var g=2*f,h=c[g],i=c[g+2],j=c[g+4],k=c[g+1],l=c[g+3],m=c[g+5],n=d[g]*a.texture.width,o=d[g+2]*a.texture.width,p=d[g+4]*a.texture.width,q=d[g+1]*a.texture.height,r=d[g+3]*a.texture.height,s=d[g+5]*a.texture.height;b.save(),b.beginPath(),b.moveTo(h,k),b.lineTo(i,l),b.lineTo(j,m),b.closePath(),b.clip();var t=n*r+q*p+o*s-r*p-q*o-n*s,u=h*r+q*j+i*s-r*j-q*i-h*s,v=n*i+h*p+o*j-i*p-h*o-n*j,w=n*r*j+q*i*p+h*o*s-h*r*p-q*o*j-n*i*s,x=k*r+q*m+l*s-r*m-q*l-k*s,y=n*l+k*p+o*m-l*p-k*o-n*m,z=n*r*m+q*l*p+k*o*s-k*r*p-q*o*m-n*l*s;b.transform(u/t,x/t,v/t,y/t,w/t,z/t),b.drawImage(a.texture.baseTexture.source,0,0),b.restore()}},f.CanvasGraphics=function(){},f.CanvasGraphics.renderGraphics=function(a,b){for(var c=a.worldAlpha,d=0;d1&&(c=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var d=0;1>d;d++){var e=a.graphicsData[d],g=e.points;if(e.type==f.Graphics.POLY){b.beginPath(),b.moveTo(g[0],g[1]);for(var h=1;hb?b:d,e=b+m>e?b+m:e,g=g>c?b:g,h=c+n>h?c+n:h}else if(k===f.Graphics.CIRC||k===f.Graphics.ELIP){b=a.x,c=a.y;var o=a.radius+l/2;d=d>b-o?b-o:d,e=b+o>e?b+o:e,g=g>c-o?c-o:g,h=c+o>h?c+o:h}else for(var p=0;pb-l?b-l:d,e=b+l>e?b+l:e,g=g>c-l?c-l:g,h=c+l>h?c+l:h}this.bounds=new f.Rectangle(d,g,e-d,h-g)}},f.Graphics.POLY=0,f.Graphics.RECT=1,f.Graphics.CIRC=2,f.Graphics.ELIP=3,f.Strip=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.blendMode=f.blendModes.NORMAL;try{this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.verticies=new Float32Array([0,0,0,0,0,0,0,0,0]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3])}catch(d){this.uvs=[0,1,1,1,1,0,0,1],this.verticies=[0,0,0,0,0,0,0,0,0],this.colors=[1,1,1,1],this.indices=[0,1,2,3]}this.width=b,this.height=c,a.baseTexture.hasLoaded?(this.width=this.texture.frame.width,this.height=this.texture.frame.height,this.updateFrame=!0):(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Strip.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Strip.prototype.constructor=f.Strip,f.Strip.prototype.setTexture=function(a){this.texture=a,this.width=a.frame.width,this.height=a.frame.height,this.updateFrame=!0},f.Strip.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Rope=function(a,b){f.Strip.call(this,a),this.points=b;try{this.verticies=new Float32Array(4*b.length),this.uvs=new Float32Array(4*b.length),this.colors=new Float32Array(2*b.length),this.indices=new Uint16Array(2*b.length)}catch(c){this.verticies=verticies,this.uvs=uvs,this.colors=colors,this.indices=indices}this.refresh()},f.Rope.prototype=Object.create(f.Strip.prototype),f.Rope.prototype.constructor=f.Rope,f.Rope.prototype.refresh=function(){var a=this.points;if(!(a.length<1)){var b=this.uvs,c=this.indices,d=this.colors,e=a[0],f=a[0];this.count-=.2,b[0]=0,b[1]=1,b[2]=0,b[3]=1,d[0]=1,d[1]=1,c[0]=0,c[1]=1;for(var g=a.length,h=1;g>h;h++){var f=a[h],i=4*h,j=h/(g-1);h%2?(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1):(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1),i=2*h,d[i]=1,d[i+1]=1,i=2*h,c[i]=i,c[i+1]=i+1,e=f}}},f.Rope.prototype.updateTransform=function(){var a=this.points;if(!(a.length<1)){var b,c=this.verticies,d=a[0],e={x:0,y:0},g=a[0];this.count-=.2,c[0]=g.x+e.x,c[1]=g.y+e.y,c[2]=g.x-e.x,c[3]=g.y-e.y;for(var h=a.length,i=1;h>i;i++){var g=a[i],j=4*i;b=i1&&(k=1);var l=Math.sqrt(e.x*e.x+e.y*e.y),m=this.texture.height/2;e.x/=l,e.y/=l,e.x*=m,e.y*=m,c[j]=g.x+e.x,c[j+1]=g.y+e.y,c[j+2]=g.x-e.x,c[j+3]=g.y-e.y,d=g}f.DisplayObjectContainer.prototype.updateTransform.call(this)}},f.Rope.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.width=b,this.height=c,this.tileScale=new f.Point(1,1),this.tilePosition=new f.Point(0,0),this.renderable=!0,this.blendMode=f.blendModes.NORMAL},f.TilingSprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.TilingSprite.prototype.constructor=f.TilingSprite,f.TilingSprite.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Spine=function(a){if(f.DisplayObjectContainer.call(this),this.spineData=f.AnimCache[a],!this.spineData)throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+a);this.skeleton=new n.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new n.AnimationStateData(this.spineData),this.state=new n.AnimationState(this.stateData),this.slotContainers=[];for(var b=0,c=this.skeleton.drawOrder.length;c>b;b++){var d=this.skeleton.drawOrder[b],e=d.attachment,g=new f.DisplayObjectContainer;if(this.slotContainers.push(g),this.addChild(g),e instanceof n.RegionAttachment){var h=e.rendererObject.name,i=this.createSprite(d,e.rendererObject);d.currentSprite=i,d.currentSpriteName=h,g.addChild(i)}}},f.Spine.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Spine.prototype.constructor=f.Spine,f.Spine.prototype.updateTransform=function(){this.lastTime=this.lastTime||Date.now();var a=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.state.update(a),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var b=this.skeleton.drawOrder,c=0,d=b.length;d>c;c++){var e=b[c],g=e.attachment,h=this.slotContainers[c];if(g instanceof n.RegionAttachment){if(g.rendererObject&&(!e.currentSpriteName||e.currentSpriteName!=g.name)){var i=g.rendererObject.name;if(void 0!==e.currentSprite&&(e.currentSprite.visible=!1),e.sprites=e.sprites||{},void 0!==e.sprites[i])e.sprites[i].visible=!0;else{var j=this.createSprite(e,g.rendererObject);h.addChild(j)}e.currentSprite=e.sprites[i],e.currentSpriteName=i}h.visible=!0;var k=e.bone;h.position.x=k.worldX+g.x*k.m00+g.y*k.m01,h.position.y=k.worldY+g.x*k.m10+g.y*k.m11,h.scale.x=k.worldScaleX,h.scale.y=k.worldScaleY,h.rotation=-(e.bone.worldRotation*Math.PI/180)}else h.visible=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.Spine.prototype.createSprite=function(a,b){var c=f.TextureCache[b.name]?b.name:b.name+".png",d=new f.Sprite(f.Texture.fromFrame(c));return d.scale=b.scale,d.rotation=b.rotation,d.anchor.x=d.anchor.y=.5,a.sprites=a.sprites||{},a.sprites[b.name]=d,d};var n={};n.BoneData=function(a,b){this.name=a,this.parent=b},n.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},n.SlotData=function(a,b){this.name=a,this.boneData=b},n.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},n.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},n.Bone.yDown=!1,n.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(a,b){var c=this.parent;null!=c?(this.worldX=this.x*c.m00+this.y*c.m01+c.worldX,this.worldY=this.x*c.m10+this.y*c.m11+c.worldY,this.worldScaleX=c.worldScaleX*this.scaleX,this.worldScaleY=c.worldScaleY*this.scaleY,this.worldRotation=c.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var d=this.worldRotation*Math.PI/180,e=Math.cos(d),f=Math.sin(d);this.m00=e*this.worldScaleX,this.m10=f*this.worldScaleX,this.m01=-f*this.worldScaleY,this.m11=e*this.worldScaleY,a&&(this.m00=-this.m00,this.m01=-this.m01),b&&(this.m10=-this.m10,this.m11=-this.m11),n.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var a=this.data;this.x=a.x,this.y=a.y,this.rotation=a.rotation,this.scaleX=a.scaleX,this.scaleY=a.scaleY}},n.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},n.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(a){this.attachment=a,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(a){this._attachmentTime=this.skeleton.time-a},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var a=this.data;this.r=a.r,this.g=a.g,this.b=a.b,this.a=a.a;for(var b=this.skeleton.data.slots,c=0,d=b.length;d>c;c++)if(b[c]==a){this.setAttachment(a.attachmentName?this.skeleton.getAttachmentBySlotIndex(c,a.attachmentName):null);break}}},n.Skin=function(a){this.name=a,this.attachments={}},n.Skin.prototype={addAttachment:function(a,b,c){this.attachments[a+":"+b]=c},getAttachment:function(a,b){return this.attachments[a+":"+b]},_attachAll:function(a,b){for(var c in b.attachments){var d=c.indexOf(":"),e=parseInt(c.substring(0,d)),f=c.substring(d+1),g=a.slots[e];if(g.attachment&&g.attachment.name==f){var h=this.getAttachment(e,f);h&&g.setAttachment(h)}}}},n.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},n.Animation.prototype={apply:function(a,b,c){c&&0!=this.duration&&(b%=this.duration);for(var d=this.timelines,e=0,f=d.length;f>e;e++)d[e].apply(a,b,1)},mix:function(a,b,c,d){c&&0!=this.duration&&(b%=this.duration);for(var e=this.timelines,f=0,g=e.length;g>f;f++)e[f].apply(a,b,d)}},n.binarySearch=function(a,b,c){var d=0,e=Math.floor(a.length/c)-2;if(0==e)return c;for(var f=e>>>1;;){if(a[(f+1)*c]<=b?d=f+1:e=f,d==e)return(d+1)*c;f=d+e>>>1}},n.linearSearch=function(a,b,c){for(var d=0,e=a.length-c;e>=d;d+=c)if(a[d]>b)return d;return-1},n.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},n.Curves.prototype={setLinear:function(a){this.curves[6*a]=0},setStepped:function(a){this.curves[6*a]=-1},setCurve:function(a,b,c,d,e){var f=.1,g=f*f,h=g*f,i=3*f,j=3*g,k=6*g,l=6*h,m=2*-b+d,n=2*-c+e,o=3*(b-d)+1,p=3*(c-e)+1,q=6*a,r=this.curves;r[q]=b*i+m*j+o*h,r[q+1]=c*i+n*j+p*h,r[q+2]=m*k+o*l,r[q+3]=n*k+p*l,r[q+4]=o*l,r[q+5]=p*l},getCurvePercent:function(a,b){b=0>b?0:b>1?1:b;var c=6*a,d=this.curves,e=d[c];if(!e)return b;if(-1==e)return 0;for(var f=d[c+1],g=d[c+2],h=d[c+3],i=d[c+4],j=d[c+5],k=e,l=f,m=8;;){if(k>=b){var n=k-e,o=l-f;return o+(l-o)*(b-n)/(k-n)}if(0==m)break;m--,e+=g,f+=h,g+=i,h+=j,k+=e,l+=f}return l+(1-l)*(b-k)/(1-k)}},n.RotateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=2*a},n.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(a,b,c){a*=2,this.frames[a]=b,this.frames[a+1]=c},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-2]){for(var f=e.data.rotation+d[d.length-1]-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;return e.rotation+=f*c,void 0}var g=n.binarySearch(d,b,2),h=d[g-1],i=d[g],j=1-(b-i)/(d[g-2]-i);j=this.curves.getCurvePercent(g/2-1,j);for(var f=d[g+1]-h;f>180;)f-=360;for(;-180>f;)f+=360;for(f=e.data.rotation+(h+f*j)-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;e.rotation+=f*c}}},n.TranslateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.x+=(e.data.x+d[d.length-2]-e.x)*c,e.y+=(e.data.y+d[d.length-1]-e.y)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.x+=(e.data.x+g+(d[f+1]-g)*j-e.x)*c,e.y+=(e.data.y+h+(d[f+2]-h)*j-e.y)*c}}},n.ScaleTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.scaleX+=(e.data.scaleX-1+d[d.length-2]-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+d[d.length-1]-e.scaleY)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.scaleX+=(e.data.scaleX-1+g+(d[f+1]-g)*j-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+h+(d[f+2]-h)*j-e.scaleY)*c}}},n.ColorTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=5*a},n.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(c,d){c*=5,this.frames[c]=d,this.frames[c+1]=r,this.frames[c+2]=g,this.frames[c+3]=b,this.frames[c+4]=a},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-5]){var f=d.length-1;return e.r=d[f-3],e.g=d[f-2],e.b=d[f-1],e.a=d[f],void 0}var g=n.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],l=d[g],m=1-(b-l)/(d[g-5]-l);m=this.curves.getCurvePercent(g/5-1,m);var o=h+(d[g+1]-h)*m,p=i+(d[g+2]-i)*m,q=j+(d[g+3]-j)*m,r=k+(d[g+4]-k)*m;1>c?(e.r+=(o-e.r)*c,e.g+=(p-e.g)*c,e.b+=(q-e.b)*c,e.a+=(r-e.a)*c):(e.r=o,e.g=p,e.b=q,e.a=r)}}},n.AttachmentTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},n.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(a,b,c){this.frames[a]=b,this.attachmentNames[a]=c},apply:function(a,b){var c=this.frames;if(!(b=c[c.length-1]?c.length-1:n.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},n.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},n.SkeletonData.prototype={defaultSkin:null,findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return slot[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSkin:function(a){for(var b=this.skins,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findAnimation:function(a){for(var b=this.animations,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null}},n.Skeleton=function(a){this.data=a,this.bones=[];for(var b=0,c=a.bones.length;c>b;b++){var d=a.bones[b],e=d.parent?this.bones[a.bones.indexOf(d.parent)]:null;this.bones.push(new n.Bone(d,e))}this.slots=[],this.drawOrder=[];for(var b=0,c=a.slots.length;c>b;b++){var f=a.slots[b],g=this.bones[a.bones.indexOf(f.boneData)],h=new n.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},n.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var a=this.flipX,b=this.flipY,c=this.bones,d=0,e=c.length;e>d;d++)c[d].updateWorldTransform(a,b)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var a=this.bones,b=0,c=a.length;c>b;b++)a[b].setToSetupPose()},setSlotsToSetupPose:function(){for(var a=this.slots,b=0,c=a.length;c>b;b++)a[b].setToSetupPose(b)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},setSkinByName:function(a){var b=this.data.findSkin(a);if(!b)throw"Skin not found: "+a;this.setSkin(b)},setSkin:function(a){this.skin&&a&&a._attachAll(this,this.skin),this.skin=a},getAttachmentBySlotName:function(a,b){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(a),b)},getAttachmentBySlotIndex:function(a,b){if(this.skin){var c=this.skin.getAttachment(a,b);if(c)return c}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(a,b):null},setAttachment:function(a,b){for(var c=this.slots,d=0,e=c.size;e>d;d++){var f=c[d];if(f.data.name==a){var g=null;if(b&&(g=this.getAttachment(d,b),null==g))throw"Attachment not found: "+b+", for slot: "+a;return f.setAttachment(g),void 0}}throw"Slot not found: "+a},update:function(a){time+=a}},n.AttachmentType={region:0},n.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},n.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(a,b,c,d,e){var f=this.uvs;e?(f[2]=a,f[3]=d,f[4]=a,f[5]=b,f[6]=c,f[7]=b,f[0]=c,f[1]=d):(f[0]=a,f[1]=d,f[2]=a,f[3]=b,f[4]=c,f[5]=b,f[6]=c,f[7]=d)},updateOffset:function(){var a=this.width/this.regionOriginalWidth*this.scaleX,b=this.height/this.regionOriginalHeight*this.scaleY,c=-this.width/2*this.scaleX+this.regionOffsetX*a,d=-this.height/2*this.scaleY+this.regionOffsetY*b,e=c+this.regionWidth*a,f=d+this.regionHeight*b,g=this.rotation*Math.PI/180,h=Math.cos(g),i=Math.sin(g),j=c*h+this.x,k=c*i,l=d*h+this.y,m=d*i,n=e*h+this.x,o=e*i,p=f*h+this.y,q=f*i,r=this.offset;r[0]=j-m,r[1]=l+k,r[2]=j-q,r[3]=p+k,r[4]=n-q,r[5]=p+o,r[6]=n-m,r[7]=l+o},computeVertices:function(a,b,c,d){a+=c.worldX,b+=c.worldY;var e=c.m00,f=c.m01,g=c.m10,h=c.m11,i=this.offset;d[0]=i[0]*e+i[1]*f+a,d[1]=i[0]*g+i[1]*h+b,d[2]=i[2]*e+i[3]*f+a,d[3]=i[2]*g+i[3]*h+b,d[4]=i[4]*e+i[5]*f+a,d[5]=i[4]*g+i[5]*h+b,d[6]=i[6]*e+i[7]*f+a,d[7]=i[6]*g+i[7]*h+b}},n.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},n.AnimationStateData.prototype={defaultMix:0,setMixByName:function(a,b,c){var d=this.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;var e=this.skeletonData.findAnimation(b);if(!e)throw"Animation not found: "+b;this.setMix(d,e,c)},setMix:function(a,b,c){this.animationToMixTime[a.name+":"+b.name]=c},getMix:function(a,b){var c=this.animationToMixTime[a.name+":"+b.name];return c?c:this.defaultMix}},n.AnimationState=function(a){this.data=a,this.queue=[]},n.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(a){if(this.currentTime+=a,this.previousTime+=a,this.mixTime+=a,this.queue.length>0){var b=this.queue[0];this.currentTime>=b.delay&&(this._setAnimation(b.animation,b.loop),this.queue.shift())}},apply:function(a){if(this.current)if(this.previous){this.previous.apply(a,this.previousTime,this.previousLoop);var b=this.mixTime/this.mixDuration;b>=1&&(b=1,this.previous=null),this.current.mix(a,this.currentTime,this.currentLoop,b)}else this.current.apply(a,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(a,b){this.previous=null,a&&this.current&&(this.mixDuration=this.data.getMix(this.current,a),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=a,this.currentLoop=b,this.currentTime=0},setAnimationByName:function(a,b){var c=this.data.skeletonData.findAnimation(a);if(!c)throw"Animation not found: "+a;this.setAnimation(c,b)},setAnimation:function(a,b){this.queue.length=0,this._setAnimation(a,b)},addAnimationByName:function(a,b,c){var d=this.data.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;this.addAnimation(d,b,c)},addAnimation:function(a,b,c){var d={};if(d.animation=a,d.loop=b,!c||0>=c){var e=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;c=null!=e?e.duration-this.data.getMix(e,a)+(c||0):0}d.delay=c,this.queue.push(d)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},n.SkeletonJson=function(a){this.attachmentLoader=a},n.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new n.SkeletonData,c=a.bones,d=0,e=c.length;e>d;d++){var f=c[d],g=null;if(f.parent&&(g=b.findBone(f.parent),!g))throw"Parent bone not found: "+f.parent;var h=new n.BoneData(f.name,g);h.length=(f.length||0)*this.scale,h.x=(f.x||0)*this.scale,h.y=(f.y||0)*this.scale,h.rotation=f.rotation||0,h.scaleX=f.scaleX||1,h.scaleY=f.scaleY||1,b.bones.push(h)}for(var i=a.slots,d=0,e=i.length;e>d;d++){var j=i[d],h=b.findBone(j.bone); -if(!h)throw"Slot bone not found: "+j.bone;var k=new n.SlotData(j.name,h),l=j.color;l&&(k.r=n.SkeletonJson.toColor(l,0),k.g=n.SkeletonJson.toColor(l,1),k.b=n.SkeletonJson.toColor(l,2),k.a=n.SkeletonJson.toColor(l,3)),k.attachmentName=j.attachment,b.slots.push(k)}var m=a.skins;for(var o in m)if(m.hasOwnProperty(o)){var p=m[o],q=new n.Skin(o);for(var r in p)if(p.hasOwnProperty(r)){var s=b.findSlotIndex(r),t=p[r];for(var u in t)if(t.hasOwnProperty(u)){var v=this.readAttachment(q,u,t[u]);null!=v&&q.addAttachment(s,u,v)}}b.skins.push(q),"default"==q.name&&(b.defaultSkin=q)}var w=a.animations;for(var x in w)w.hasOwnProperty(x)&&this.readAnimation(x,w[x],b);return b},readAttachment:function(a,b,c){b=c.name||b;var d=n.AttachmentType[c.type||"region"];if(d==n.AttachmentType.region){var e=new n.RegionAttachment;return e.x=(c.x||0)*this.scale,e.y=(c.y||0)*this.scale,e.scaleX=c.scaleX||1,e.scaleY=c.scaleY||1,e.rotation=c.rotation||0,e.width=(c.width||32)*this.scale,e.height=(c.height||32)*this.scale,e.updateOffset(),e.rendererObject={},e.rendererObject.name=b,e.rendererObject.scale={},e.rendererObject.scale.x=e.scaleX,e.rendererObject.scale.y=e.scaleY,e.rendererObject.rotation=-e.rotation*Math.PI/180,e}throw"Unknown attachment type: "+d},readAnimation:function(a,b,c){var d=[],e=0,f=b.bones;for(var g in f)if(f.hasOwnProperty(g)){var h=c.findBoneIndex(g);if(-1==h)throw"Bone not found: "+g;var i=f[g];for(var j in i)if(i.hasOwnProperty(j)){var k=i[j];if("rotate"==j){var l=new n.RotateTimeline(k.length);l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m,q.time,q.angle),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[2*l.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var l,r=1;"scale"==j?l=new n.ScaleTimeline(k.length):(l=new n.TranslateTimeline(k.length),r=this.scale),l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;l.setFrame(m,q.time,s,t),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[3*l.getFrameCount()-3])}}}var u=b.slots;for(var v in u)if(u.hasOwnProperty(v)){var w=u[v],x=c.findSlotIndex(v);for(var j in w)if(w.hasOwnProperty(j)){var k=w[j];if("color"==j){var l=new n.ColorTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=n.SkeletonJson.toColor(y,0),A=n.SkeletonJson.toColor(y,1),B=n.SkeletonJson.toColor(y,2),C=n.SkeletonJson.toColor(y,3);l.setFrame(m,q.time,z,A,B,C),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[5*l.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var l=new n.AttachmentTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m++,q.time,q.name)}d.push(l),e=Math.max(e,l.frames[l.getFrameCount()-1])}}}c.animations.push(new n.Animation(a,d,e))}},n.SkeletonJson.readCurve=function(a,b,c){var d=c.curve;d&&("stepped"==d?a.curves.setStepped(b):d instanceof Array&&a.curves.setCurve(b,d[0],d[1],d[2],d[3]))},n.SkeletonJson.toColor=function(a,b){if(8!=a.length)throw"Color hexidecimal length must be 8, recieved: "+a;return parseInt(a.substring(2*b,2),16)/255},n.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new n.AtlasReader(a),d=[];d.length=4;for(var e=null;;){var f=c.readLine();if(null==f)break;if(f=c.trim(f),0==f.length)e=null;else if(e){var g=new n.AtlasRegion;g.name=f,g.page=e,g.rotate="true"==c.readValue(),c.readTuple(d);var h=parseInt(d[0]),i=parseInt(d[1]);c.readTuple(d);var j=parseInt(d[0]),k=parseInt(d[1]);g.u=h/e.width,g.v=i/e.height,g.rotate?(g.u2=(h+k)/e.width,g.v2=(i+j)/e.height):(g.u2=(h+j)/e.width,g.v2=(i+k)/e.height),g.x=h,g.y=i,g.width=Math.abs(j),g.height=Math.abs(k),4==c.readTuple(d)&&(g.splits=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],4==c.readTuple(d)&&(g.pads=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],c.readTuple(d))),g.originalWidth=parseInt(d[0]),g.originalHeight=parseInt(d[1]),c.readTuple(d),g.offsetX=parseInt(d[0]),g.offsetY=parseInt(d[1]),g.index=parseInt(c.readValue()),this.regions.push(g)}else{e=new n.AtlasPage,e.name=f,e.format=n.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=n.Atlas.TextureFilter[d[0]],e.magFilter=n.Atlas.TextureFilter[d[1]];var l=c.readValue();e.uWrap=n.Atlas.TextureWrap.clampToEdge,e.vWrap=n.Atlas.TextureWrap.clampToEdge,"x"==l?e.uWrap=n.Atlas.TextureWrap.repeat:"y"==l?e.vWrap=n.Atlas.TextureWrap.repeat:"xy"==l&&(e.uWrap=e.vWrap=n.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},n.Atlas.prototype={findRegion:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},dispose:function(){for(var a=this.pages,b=0,c=a.length;c>b;b++)this.textureLoader.unload(a[b].rendererObject)},updateUVs:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++){var e=b[c];e.page==a&&(e.u=e.x/a.width,e.v=e.y/a.height,e.rotate?(e.u2=(e.x+e.height)/a.width,e.v2=(e.y+e.width)/a.height):(e.u2=(e.x+e.width)/a.width,e.v2=(e.y+e.height)/a.height))}}},n.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},n.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},n.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},n.AtlasPage=function(){},n.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},n.AtlasRegion=function(){},n.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},n.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},n.AtlasReader.prototype={index:0,trim:function(a){return a.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var a=this.readLine(),b=a.indexOf(":");if(-1==b)throw"Invalid line: "+a;return this.trim(a.substring(b+1))},readTuple:function(a){var b=this.readLine(),c=b.indexOf(":");if(-1==c)throw"Invalid line: "+b;for(var d=0,e=c+1;3>d;d++){var f=b.indexOf(",",e);if(-1==f){if(0==d)throw"Invalid line: "+b;break}a[d]=this.trim(b.substr(e,f-e)),e=f+1}return a[d]=this.trim(b.substring(e)),d+1}},n.AtlasAttachmentLoader=function(a){this.atlas=a},n.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case n.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new n.RegionAttachment(c);return e.rendererObject=d,e.setUVs(d.u,d.v,d.u2,d.v2,d.rotate),e.regionOffsetX=d.offsetX,e.regionOffsetY=d.offsetY,e.regionWidth=d.width,e.regionHeight=d.height,e.regionOriginalWidth=d.originalWidth,e.regionOriginalHeight=d.originalHeight,e}throw"Unknown attachment type: "+b}},f.AnimCache={},n.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this),this.renderable=!0},f.CustomRenderable.prototype=Object.create(f.DisplayObject.prototype),f.CustomRenderable.prototype.constructor=f.CustomRenderable,f.CustomRenderable.prototype.renderCanvas=function(){},f.CustomRenderable.prototype.initWebGL=function(){},f.CustomRenderable.prototype.renderWebGL=function(){},f.BaseTextureCache={},f.texturesToUpdate=[],f.texturesToDestroy=[],f.BaseTexture=function(a){if(f.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=a,a){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);else{var b=this;this.source.onload=function(){b.hasLoaded=!0,b.width=b.source.width,b.height=b.source.height,f.texturesToUpdate.push(b),b.dispatchEvent({type:"loaded",content:b})}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);this._powerOf2=!1}},f.BaseTexture.prototype.constructor=f.BaseTexture,f.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,f.texturesToDestroy.push(this)},f.BaseTexture.fromImage=function(a,b){var c=f.BaseTextureCache[a];if(!c){var d=new Image;b&&(d.crossOrigin=""),d.src=a,c=new f.BaseTexture(d),f.BaseTextureCache[a]=c}return c},f.TextureCache={},f.FrameCache={},f.Texture=function(a,b){if(f.EventTarget.call(this),b||(this.noFrame=!0,b=new f.Rectangle(0,0,1,1)),a instanceof f.Texture&&(a=a.baseTexture),this.baseTexture=a,this.frame=b,this.trim=new f.Point,this.scope=this,a.hasLoaded)this.noFrame&&(b=new f.Rectangle(0,0,a.width,a.height)),this.setFrame(b);else{var c=this;a.addEventListener("loaded",function(){c.onBaseTextureLoaded()})}},f.Texture.prototype.constructor=f.Texture,f.Texture.prototype.onBaseTextureLoaded=function(){var a=this.baseTexture;a.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new f.Rectangle(0,0,a.width,a.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},f.Texture.prototype.destroy=function(a){a&&this.baseTexture.destroy()},f.Texture.prototype.setFrame=function(a){if(this.frame=a,this.width=a.width,this.height=a.height,a.x+a.width>this.baseTexture.width||a.y+a.height>this.baseTexture.height)throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,f.Texture.frameUpdates.push(this)},f.Texture.fromImage=function(a,b){var c=f.TextureCache[a];return c||(c=new f.Texture(f.BaseTexture.fromImage(a,b)),f.TextureCache[a]=c),c},f.Texture.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache "+this);return b},f.Texture.fromCanvas=function(a){var b=new f.BaseTexture(a);return new f.Texture(b)},f.Texture.addTextureToCache=function(a,b){f.TextureCache[b]=a},f.Texture.removeTextureFromCache=function(a){var b=f.TextureCache[a];return f.TextureCache[a]=null,b},f.Texture.frameUpdates=[],f.RenderTexture=function(a,b){f.EventTarget.call(this),this.width=a||100,this.height=b||100,this.indetityMatrix=f.mat3.create(),this.frame=new f.Rectangle(0,0,this.width,this.height),f.gl?this.initWebGL():this.initCanvas()},f.RenderTexture.prototype=Object.create(f.Texture.prototype),f.RenderTexture.prototype.constructor=f.RenderTexture,f.RenderTexture.prototype.initWebGL=function(){var a=f.gl;this.glFramebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new f.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.baseTexture._glTexture),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,this.width,this.height,0,a.RGBA,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new f.Point(this.width/2,-this.height/2),this.render=this.renderWebGL},f.RenderTexture.prototype.resize=function(a,b){if(this.width=a,this.height=b,f.gl){this.projection.x=this.width/2,this.projection.y=-this.height/2;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.baseTexture._glTexture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,this.width,this.height,0,c.RGBA,c.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height)},f.RenderTexture.prototype.initCanvas=function(){this.renderer=new f.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new f.BaseTexture(this.renderer.view),this.frame=new f.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},f.RenderTexture.prototype.renderWebGL=function(a,b,c){var d=f.gl;d.colorMask(!0,!0,!0,!0),d.viewport(0,0,this.width,this.height),d.bindFramebuffer(d.FRAMEBUFFER,this.glFramebuffer),c&&(d.clearColor(0,0,0,0),d.clear(d.COLOR_BUFFER_BIT));var e=a.children,g=a.worldTransform;a.worldTransform=f.mat3.create(),a.worldTransform[4]=-1,a.worldTransform[5]=-2*this.projection.y,b&&(a.worldTransform[2]=b.x,a.worldTransform[5]-=b.y),f.visibleCount++,a.vcount=f.visibleCount;for(var h=0,i=e.length;i>h;h++)e[h].updateTransform();var j=a.__renderGroup;j?a==j.root?j.render(this.projection,this.glFramebuffer):j.renderSpecific(a,this.projection,this.glFramebuffer):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection,this.glFramebuffer)),a.worldTransform=g},f.RenderTexture.prototype.renderCanvas=function(a,b,c){var d=a.children;a.worldTransform=f.mat3.create(),b&&(a.worldTransform[2]=b.x,a.worldTransform[5]=b.y);for(var e=0,g=d.length;g>e;e++)d[e].updateTransform();c&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(a),this.renderer.context.setTransform(1,0,0,1,0,0)},f.AssetLoader=function(a,b){f.EventTarget.call(this),this.assetURLs=a,this.crossorigin=b,this.loadersByType={jpg:f.ImageLoader,jpeg:f.ImageLoader,png:f.ImageLoader,gif:f.ImageLoader,json:f.JsonLoader,anim:f.SpineLoader,xml:f.BitmapFontLoader,fnt:f.BitmapFontLoader}},f.AssetLoader.prototype.constructor=f.AssetLoader,f.AssetLoader.prototype.load=function(){var a=this;this.loadCount=this.assetURLs.length;for(var b=0;bh;h++)for(var i=0;d>i;i++,g++){var j=new f.Texture(this.texture,{x:i*a,y:h*b,width:a,height:b});this.frames.push(j),c&&(f.TextureCache[c+"-"+g]=j)}if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var k=this;this.texture.baseTexture.addEventListener("loaded",function(){k.onLoaded()})}},f.BitmapFontLoader=function(a,b){f.EventTarget.call(this),this.url=a,this.crossorigin=b,this.baseUrl=a.replace(/[^\/]*$/,""),this.texture=null},f.BitmapFontLoader.prototype.constructor=f.BitmapFontLoader,f.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var a=this;this.ajaxRequest.onreadystatechange=function(){a.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},f.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var a=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,b=new f.ImageLoader(a,this.crossorigin);this.texture=b.texture.baseTexture;var c={},d=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],e=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];c.font=d.attributes.getNamedItem("face").nodeValue,c.size=parseInt(d.attributes.getNamedItem("size").nodeValue,10),c.lineHeight=parseInt(e.attributes.getNamedItem("lineHeight").nodeValue,10),c.chars={};for(var g=this.ajaxRequest.responseXML.getElementsByTagName("char"),h=0;h>16&255)/255,(a>>8&255)/255,(255&a)/255]}function d(a){return[(a>>16&255)/255,(a>>8&255)/255,(255&a)/255]}var e=this,f=f||{};f.Point=function(a,b){this.x=a||0,this.y=b||0},f.Point.prototype.clone=function(){return new f.Point(this.x,this.y)},f.Point.prototype.constructor=f.Point,f.Rectangle=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Rectangle.prototype.clone=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Rectangle.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=this.x;if(a>=c&&a<=c+this.width){var d=this.y;if(b>=d&&b<=d+this.height)return!0}return!1},f.Rectangle.prototype.constructor=f.Rectangle,f.Polygon=function(a){if(a instanceof Array||(a=Array.prototype.slice.call(arguments)),"number"==typeof a[0]){for(var b=[],c=0,d=a.length;d>c;c+=2)b.push(new f.Point(a[c],a[c+1]));a=b}this.points=a},f.Polygon.prototype.clone=function(){for(var a=[],b=0;bb!=i>b&&(h-f)*(b-g)/(i-g)+f>a;j&&(c=!c)}return c},f.Polygon.prototype.constructor=f.Polygon,f.Circle=function(a,b,c){this.x=a||0,this.y=b||0,this.radius=c||0},f.Circle.prototype.clone=function(){return new f.Circle(this.x,this.y,this.radius)},f.Circle.prototype.contains=function(a,b){if(this.radius<=0)return!1;var c=this.x-a,d=this.y-b,e=this.radius*this.radius;return c*=c,d*=d,e>=c+d},f.Circle.prototype.constructor=f.Circle,f.Ellipse=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Ellipse.prototype.clone=function(){return new f.Ellipse(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=(a-this.x)/this.width-.5,d=(b-this.y)/this.height-.5;return c*=c,d*=d,.25>c+d},f.Ellipse.getBounds=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.constructor=f.Ellipse,c(),f.mat3={},f.mat3.create=function(){var a=new f.Matrix(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat3.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat4={},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat3.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=m*d+n*g+o*j,c[1]=m*e+n*h+o*k,c[2]=m*f+n*i+o*l,c[3]=p*d+q*g+r*j,c[4]=p*e+q*h+r*k,c[5]=p*f+q*i+r*l,c[6]=s*d+t*g+u*j,c[7]=s*e+t*h+u*k,c[8]=s*f+t*i+u*l,c},f.mat3.clone=function(a){var b=new f.Matrix(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.mat3.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.mat3.toMat4=function(a,b){return b||(b=f.mat4.create()),b[15]=1,b[14]=0,b[13]=0,b[12]=0,b[11]=0,b[10]=a[8],b[9]=a[7],b[8]=a[6],b[7]=0,b[6]=a[5],b[5]=a[4],b[4]=a[3],b[3]=0,b[2]=a[2],b[1]=a[1],b[0]=a[0],b},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat4.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},f.mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,t=b[4],u=b[5],v=b[6],w=b[7],c[4]=t*d+u*h+v*l+w*p,c[5]=t*e+u*i+v*m+w*q,c[6]=t*f+u*j+v*n+w*r,c[7]=t*g+u*k+v*o+w*s,t=b[8],u=b[9],v=b[10],w=b[11],c[8]=t*d+u*h+v*l+w*p,c[9]=t*e+u*i+v*m+w*q,c[10]=t*f+u*j+v*n+w*r,c[11]=t*g+u*k+v*o+w*s,t=b[12],u=b[13],v=b[14],w=b[15],c[12]=t*d+u*h+v*l+w*p,c[13]=t*e+u*i+v*m+w*q,c[14]=t*f+u*j+v*n+w*r,c[15]=t*g+u*k+v*o+w*s,c},f.DisplayObject=function(){this.last=this,this.first=this,this.position=new f.Point,this.scale=new f.Point(1,1),this.pivot=new f.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.parent=null,this.stage=null,this.worldAlpha=1,this._interactive=!1,this.worldTransform=f.mat3.create(),this.localTransform=f.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1,this.filterArea=new f.Rectangle(0,0,1,1)},f.DisplayObject.prototype.constructor=f.DisplayObject,f.DisplayObject.prototype.setInteractive=function(a){this.interactive=a},Object.defineProperty(f.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(a){this._interactive=a,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(f.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(a){a?this._mask?(a.start=this._mask.start,a.end=this._mask.end):(this.addFilter(a),a.renderable=!1):(this.removeFilter(this._mask),this._mask.renderable=!0),this._mask=a}}),Object.defineProperty(f.DisplayObject.prototype,"filters",{get:function(){return this._filters},set:function(a){if(a){this._filters&&this.removeFilter(this._filters),this.addFilter(a);for(var b=[],c=0;c=0&&b<=this.children.length))throw new Error(a+" The index "+b+" supplied is out of bounds "+this.children.length);if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.stage){var c=a;do c.interactive&&(this.stage.dirty=!0),c.stage=this.stage,c=c._iNext;while(c)}var d,e,f=a.first,g=a.last;if(b==this.children.length){e=this.last;for(var h=this,i=this.last;h;)h.last==i&&(h.last=a.last),h=h.parent}else e=0==b?this:this.children[b-1].last;d=e._iNext,d&&(d._iPrev=g,g._iNext=d),f._iPrev=e,e._iNext=f,this.children.splice(b,0,a),this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.swapChildren=function(){},f.DisplayObjectContainer.prototype.getChildAt=function(a){if(a>=0&&aa;a++)this.children[a].updateTransform()}},f.blendModes={},f.blendModes.NORMAL=0,f.blendModes.SCREEN=1,f.Sprite=function(a){f.DisplayObjectContainer.call(this),this.anchor=new f.Point,this.texture=a,this.blendMode=f.blendModes.NORMAL,this._width=0,this._height=0,a.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Sprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Sprite.prototype.constructor=f.Sprite,Object.defineProperty(f.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(a){this.scale.x=a/this.texture.frame.width,this._width=a}}),Object.defineProperty(f.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(a){this.scale.y=a/this.texture.frame.height,this._height=a}}),f.Sprite.prototype.setTexture=function(a){this.texture.baseTexture!=a.baseTexture?(this.textureChange=!0,this.texture=a,this.__renderGroup&&this.__renderGroup.updateTexture(this)):this.texture=a,this.updateFrame=!0},f.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},f.Sprite.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache"+this);return new f.Sprite(b)},f.Sprite.fromImage=function(a){var b=f.Texture.fromImage(a);return new f.Sprite(b)},f.MovieClip=function(a){f.Sprite.call(this,a[0]),this.textures=a,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},f.MovieClip.prototype=Object.create(f.Sprite.prototype),f.MovieClip.prototype.constructor=f.MovieClip,Object.defineProperty(f.MovieClip.prototype,"totalFrames",{get:function(){return this.textures.length}}),f.MovieClip.prototype.stop=function(){this.playing=!1},f.MovieClip.prototype.play=function(){this.playing=!0},f.MovieClip.prototype.gotoAndStop=function(a){this.playing=!1,this.currentFrame=a;var b=this.currentFrame+.5|0;this.setTexture(this.textures[b%this.textures.length])},f.MovieClip.prototype.gotoAndPlay=function(a){this.currentFrame=a,this.playing=!0},f.MovieClip.prototype.updateTransform=function(){if(f.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var a=this.currentFrame+.5|0;this.loop||a=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},f.FilterBlock=function(){this.visible=!0,this.renderable=!0},f.Text=function(a,b){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),f.Sprite.call(this,f.Texture.fromCanvas(this.canvas)),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.Text.prototype=Object.create(f.Sprite.prototype),f.Text.prototype.constructor=f.Text,f.Text.prototype.setStyle=function(a){a=a||{},a.font=a.font||"bold 20pt Arial",a.fill=a.fill||"black",a.align=a.align||"left",a.stroke=a.stroke||"black",a.strokeThickness=a.strokeThickness||0,a.wordWrap=a.wordWrap||!1,a.wordWrapWidth=a.wordWrapWidth||100,this.style=a,this.dirty=!0},f.Text.prototype.setText=function(a){this.text=a.toString()||" ",this.dirty=!0},f.Text.prototype.updateText=function(){this.context.font=this.style.font;var a=this.text;this.style.wordWrap&&(a=this.wordWrap(this.text));for(var b=a.split(/(?:\r\n|\r|\n)/),c=[],d=0,e=0;ee?(g>0&&(b+="\n"),b+=f[g]+" ",e=this.style.wordWrapWidth-h):(e-=i,b+=f[g]+" ")}b+="\n"}return b},f.Text.prototype.destroy=function(a){a&&this.texture.destroy()},f.Text.heightCache={},f.BitmapText=function(a,b){f.DisplayObjectContainer.call(this),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.BitmapText.prototype=Object.create(f.DisplayObjectContainer.prototype),f.BitmapText.prototype.constructor=f.BitmapText,f.BitmapText.prototype.setText=function(a){this.text=a||" ",this.dirty=!0},f.BitmapText.prototype.setStyle=function(a){a=a||{},a.align=a.align||"left",this.style=a;var b=a.font.split(" ");this.fontName=b[b.length-1],this.fontSize=b.length>=2?parseInt(b[b.length-2],10):f.BitmapText.fonts[this.fontName].size,this.dirty=!0},f.BitmapText.prototype.updateText=function(){for(var a=f.BitmapText.fonts[this.fontName],b=new f.Point,c=null,d=[],e=0,g=[],h=0,i=this.fontSize/a.size,j=0;j=j;j++){var n=0;"right"==this.style.align?n=e-g[j]:"center"==this.style.align&&(n=(e-g[j])/2),m.push(n)}for(j=0;j0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.BitmapText.fonts={},f.InteractionManager=function(a){this.stage=a,this.mouse=new f.InteractionData,this.touchs={},this.tempPoint=new f.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0},f.InteractionManager.prototype.constructor=f.InteractionManager,f.InteractionManager.prototype.collectInteractiveSprite=function(a,b){for(var c=a.children,d=c.length,e=d-1;e>=0;e--){var f=c[e];f.interactive?(b.interactiveChildren=!0,this.interactiveItems.push(f),f.children.length>0&&this.collectInteractiveSprite(f,f)):(f.__iParent=null,f.children.length>0&&this.collectInteractiveSprite(f,b))}},f.InteractionManager.prototype.setTarget=function(a){this.target=a,null===this.interactionDOMElement&&this.setTargetDomElement(a.view),document.body.addEventListener("mouseup",this.onMouseUp,!0)},f.InteractionManager.prototype.setTargetDomElement=function(a){null!==this.interactionDOMElement&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]="",this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0)),window.navigator.msPointerEnabled&&(a.style["-ms-content-zooming"]="none",a.style["-ms-touch-action"]="none"),this.interactionDOMElement=a,a.addEventListener("mousemove",this.onMouseMove,!0),a.addEventListener("mousedown",this.onMouseDown,!0),a.addEventListener("mouseout",this.onMouseOut,!0),a.addEventListener("touchstart",this.onTouchStart,!0),a.addEventListener("touchend",this.onTouchEnd,!0),a.addEventListener("touchmove",this.onTouchMove,!0)},f.InteractionManager.prototype.update=function(){if(this.target){var a=Date.now(),b=a-this.last;if(b=30*b/1e3,!(1>b)){if(this.last=a,this.dirty){this.dirty=!1;for(var c=this.interactiveItems.length,d=0;c>d;d++)this.interactiveItems[d].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var e=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var d=0;e>d;d++){var f=this.interactiveItems[d];(f.mouseover||f.mouseout||f.buttonMode)&&(f.__hit=this.hitTest(f,this.mouse),this.mouse.target=f,f.__hit?(f.buttonMode&&(this.interactionDOMElement.style.cursor="pointer"),f.__isOver||(f.mouseover&&f.mouseover(this.mouse),f.__isOver=!0)):f.__isOver&&(f.mouseout&&f.mouseout(this.mouse),f.__isOver=!1))}}}},f.InteractionManager.prototype.onMouseMove=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(a.clientX-b.left)*(this.target.width/b.width),this.mouse.global.y=(a.clientY-b.top)*(this.target.height/b.height);for(var c=this.interactiveItems.length,d=(this.mouse.global,0);c>d;d++){var e=this.interactiveItems[d];e.mousemove&&e.mousemove(this.mouse)}},f.InteractionManager.prototype.onMouseDown=function(a){this.mouse.originalEvent=a||window.event;for(var b=this.interactiveItems.length,c=(this.mouse.global,this.stage,0);b>c;c++){var d=this.interactiveItems[c];if((d.mousedown||d.click)&&(d.__mouseIsDown=!0,d.__hit=this.hitTest(d,this.mouse),d.__hit&&(d.mousedown&&d.mousedown(this.mouse),d.__isDown=!0,!d.interactiveChildren)))break}},f.InteractionManager.prototype.onMouseOut=function(){var a=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var b=0;a>b;b++){var c=this.interactiveItems[b];c.__isOver&&(this.mouse.target=c,c.mouseout&&c.mouseout(this.mouse),c.__isOver=!1)}},f.InteractionManager.prototype.onMouseUp=function(a){this.mouse.originalEvent=a||window.event;for(var b=(this.mouse.global,this.interactiveItems.length),c=!1,d=0;b>d;d++){var e=this.interactiveItems[d];(e.mouseup||e.mouseupoutside||e.click)&&(e.__hit=this.hitTest(e,this.mouse),e.__hit&&!c?(e.mouseup&&e.mouseup(this.mouse),e.__isDown&&e.click&&e.click(this.mouse),e.interactiveChildren||(c=!0)):e.__isDown&&e.mouseupoutside&&e.mouseupoutside(this.mouse),e.__isDown=!1)}},f.InteractionManager.prototype.hitTest=function(a,b){var c=b.global;if(a.vcount!==f.visibleCount)return!1;var d=a instanceof f.Sprite,e=a.worldTransform,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=1/(g*k+h*-j),n=k*m*c.x+-h*m*c.y+(l*h-i*k)*m,o=g*m*c.y+-j*m*c.x+(-l*g+i*j)*m;if(b.target=a,a.hitArea&&a.hitArea.contains)return a.hitArea.contains(n,o)?(b.target=a,!0):!1;if(d){var p,q=a.texture.frame.width,r=a.texture.frame.height,s=-q*a.anchor.x;if(n>s&&s+q>n&&(p=-r*a.anchor.y,o>p&&p+r>o))return b.target=a,!0}for(var t=a.children.length,u=0;t>u;u++){var v=a.children[u],w=this.hitTest(v,b);if(w)return b.target=a,!0}return!1},f.InteractionManager.prototype.onTouchMove=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;dd;d++){var h=this.interactiveItems[d];h.touchmove&&h.touchmove(f)}},f.InteractionManager.prototype.onTouchStart=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i];if((j.touchstart||j.tap)&&(j.__hit=this.hitTest(j,g),j.__hit&&(j.touchstart&&j.touchstart(g),j.__isDown=!0,j.__touchData=g,!j.interactiveChildren)))break}}},f.InteractionManager.prototype.onTouchEnd=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i],k=j.__touchData;j.__hit=this.hitTest(j,f),k==f&&(f.originalEvent=a||window.event,(j.touchend||j.tap)&&(j.__hit&&!g?(j.touchend&&j.touchend(f),j.__isDown&&j.tap&&j.tap(f),j.interactiveChildren||(g=!0)):j.__isDown&&j.touchendoutside&&j.touchendoutside(f),j.__isDown=!1),j.__touchData=null)}this.pool.push(f),this.touchs[e.identifier]=null}},f.InteractionData=function(){this.global=new f.Point,this.local=new f.Point,this.target,this.originalEvent},f.InteractionData.prototype.getLocalPosition=function(a){var b=a.worldTransform,c=this.global,d=b[0],e=b[1],g=b[2],h=b[3],i=b[4],j=b[5],k=1/(d*i+e*-h);return new f.Point(i*k*c.x+-e*k*c.y+(j*e-g*i)*k,d*k*c.y+-h*k*c.x+(-j*d+g*h)*k)},f.InteractionData.prototype.constructor=f.InteractionData,f.Stage=function(a){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=!0,this.interactionManager=new f.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new f.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(a),this.worldVisible=!0},f.Stage.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Stage.prototype.constructor=f.Stage,f.Stage.prototype.setInteractionDelegate=function(a){this.interactionManager.setTargetDomElement(a)},f.Stage.prototype.updateTransform=function(){this.worldAlpha=1,this.vcount=f.visibleCount;for(var a=0,b=this.children.length;b>a;a++)this.children[a].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},f.Stage.prototype.setBackgroundColor=function(a){this.backgroundColor=a||0,this.backgroundColorSplit=d(this.backgroundColor);var b=this.backgroundColor.toString(16);b="000000".substr(0,6-b.length)+b,this.backgroundColorString="#"+b},f.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var h=0,i=["ms","moz","webkit","o"],j=0;j>>>>>>>>"),console.log("_");var b=0,c=a.first;for(console.log(c);c._iNext;)if(b++,c=c._iNext,console.log(c),b>100){console.log("BREAK");break}},f.EventTarget=function(){var a={};this.addEventListener=this.on=function(b,c){void 0===a[b]&&(a[b]=[]),-1===a[b].indexOf(c)&&a[b].push(c)},this.dispatchEvent=this.emit=function(b){if(a[b.type]&&a[b.type].length)for(var c=0,d=a[b.type].length;d>c;c++)a[b.type][c](b)},this.removeEventListener=this.off=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}},f.autoDetectRenderer=function(a,b,c,d,e){a||(a=800),b||(b=600);var g=function(){try{var a=document.createElement("canvas");return!!window.WebGLRenderingContext&&(a.getContext("webgl")||a.getContext("experimental-webgl"))}catch(b){return!1}}();if(g){var h=-1!=navigator.userAgent.toLowerCase().indexOf("msie");g=!h}return g?new f.WebGLRenderer(a,b,c,d,e):new f.CanvasRenderer(a,b,c,d)},f.PolyK={},f.PolyK.Triangulate=function(a){var b=!0,c=a.length>>1;if(3>c)return[];for(var d=[],e=[],g=0;c>g;g++)e.push(g);for(var g=0,h=c;h>3;){var i=e[(g+0)%h],j=e[(g+1)%h],k=e[(g+2)%h],l=a[2*i],m=a[2*i+1],n=a[2*j],o=a[2*j+1],p=a[2*k],q=a[2*k+1],r=!1;if(f.PolyK._convex(l,m,n,o,p,q,b)){r=!0;for(var s=0;h>s;s++){var t=e[s];if(t!=i&&t!=j&&t!=k&&f.PolyK._PointInTriangle(a[2*t],a[2*t+1],l,m,n,o,p,q)){r=!1;break}}}if(r)d.push(i,j,k),e.splice((g+1)%h,1),h--,g=0;else if(g++>3*h){if(!b)return console.log("PIXI Warning: shape too complex to fill"),[];var d=[];e=[];for(var g=0;c>g;g++)e.push(g);g=0,h=c,b=!1}}return d.push(e[0],e[1],e[2]),d},f.PolyK._PointInTriangle=function(a,b,c,d,e,f,g,h){var i=g-c,j=h-d,k=e-c,l=f-d,m=a-c,n=b-d,o=i*i+j*j,p=i*k+j*l,q=i*m+j*n,r=k*k+l*l,s=k*m+l*n,t=1/(o*r-p*p),u=(r*q-p*s)*t,v=(o*s-p*q)*t;return u>=0&&v>=0&&1>u+v},f.PolyK._convex=function(a,b,c,d,e,f,g){return(b-d)*(e-c)+(c-a)*(f-d)>=0==g},f.initDefaultShaders=function(){f.primitiveShader=new f.PrimitiveShader,f.primitiveShader.init(),f.stripShader=new f.StripShader,f.stripShader.init(),f.defaultShader=new f.PixiShader,f.defaultShader.init();var a=f.gl,b=f.defaultShader.program;a.useProgram(b),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.primitiveShader.program),a.disableVertexAttribArray(f.defaultShader.aVertexPosition),a.disableVertexAttribArray(f.defaultShader.colorAttribute),a.disableVertexAttribArray(f.defaultShader.aTextureCoord),a.enableVertexAttribArray(f.primitiveShader.aVertexPosition),a.enableVertexAttribArray(f.primitiveShader.colorAttribute)},f.deactivatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program),a.disableVertexAttribArray(f.primitiveShader.aVertexPosition),a.disableVertexAttribArray(f.primitiveShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aVertexPosition),a.enableVertexAttribArray(f.defaultShader.colorAttribute),a.enableVertexAttribArray(f.defaultShader.aTextureCoord)},f.activateStripShader=function(){var a=f.gl;a.useProgram(f.stripShader.program)},f.deactivateStripShader=function(){var a=f.gl;a.useProgram(f.defaultShader.program)},f.CompileVertexShader=function(a,b){return f._CompileShader(a,b,a.VERTEX_SHADER)},f.CompileFragmentShader=function(a,b){return f._CompileShader(a,b,a.FRAGMENT_SHADER)},f._CompileShader=function(a,b,c){var d=b.join("\n"),e=a.createShader(c);return a.shaderSource(e,d),a.compileShader(e),a.getShaderParameter(e,a.COMPILE_STATUS)?e:(console.log(a.getShaderInfoLog(e)),null)},f.compileProgram=function(a,b){var c=f.gl,d=f.CompileFragmentShader(c,b),e=f.CompileVertexShader(c,a),g=c.createProgram();return c.attachShader(g,e),c.attachShader(g,d),c.linkProgram(g),c.getProgramParameter(g,c.LINK_STATUS)||console.log("Could not initialise shaders"),g},f.PixiShader=function(){this.program,this.fragmentSrc=["precision lowp float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;","}"],this.textureCount=0},f.PixiShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc||f.PixiShader.defaultVertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"); +for(var c in this.uniforms)this.uniforms[c].uniformLocation=b.getUniformLocation(a,c);this.program=a},f.PixiShader.prototype.syncUniforms=function(){this.textureCount=1;var a=f.gl;for(var b in this.uniforms){var c=this.uniforms[b].type,d=!1;if(this.uniforms[b].transpose&&(d=this.uniforms[b].transpose),"1f"==c)a.uniform1f(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1fv"==c)a.uniform1fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1i"==c)a.uniform1i(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("1iv"==c)a.uniform1i(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("2f"==c)a.uniform2f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("2fv"==c)a.uniform2fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("2i"==c)a.uniform2i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y);else if("2iv"==c)a.uniform2iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("3f"==c)a.uniform3f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z);else if("3fv"==c)a.uniform3fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("3i"==c)a.uniform3i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z);else if("3iv"==c)a.uniform3iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("4f"==c)a.uniform4f(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z,this.uniforms[b].value.w);else if("4fv"==c)a.uniform4fv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("4i"==c)a.uniform4i(this.uniforms[b].uniformLocation,this.uniforms[b].value.x,this.uniforms[b].value.y,this.uniforms[b].value.z,this.uniforms[b].value.w);else if("4iv"==c)a.uniform4iv(this.uniforms[b].uniformLocation,this.uniforms[b].value);else if("mat2"==c)a.uniformMatrix2fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("mat3"==c)a.uniformMatrix3fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("mat4"==c)a.uniformMatrix4fv(this.uniforms[b].uniformLocation,d,this.uniforms[b].value);else if("sampler2D"==c&&this.uniforms[b].value.baseTexture.hasLoaded){var e=this.uniforms[b].value.baseTexture._glTexture,g=this.uniforms[b].value.baseTexture.source,h=a.RGBA;this.uniforms[b].format&&"luminance"==this.uniforms[b].format&&(h=a.LUMINANCE),a.activeTexture(a["TEXTURE"+this.textureCount]),this.uniforms[b].wrap?"no-repeat"==this.uniforms[b].wrap||this.uniforms[b].wrap===!1?this.createGLTextureLinear(a,g,e):"repeat"==this.uniforms[b].wrap||this.uniforms[b].wrap===!0?this.createGLTexture(a,g,h,e):"nearest-repeat"==this.uniforms[b].wrap?this.createGLTextureNearestRepeat(a,g,e):"nearest"==this.uniforms[b].wrap?this.createGLTextureNearest(a,g,e):"audio"==this.uniforms[b].wrap?this.createAudioTexture(a,e):"keyboard"==this.uniforms[b].wrap&&this.createKeyboardTexture(a,e):this.createGLTextureLinear(a,g,e),a.uniform1i(this.uniforms[b].uniformLocation,this.textureCount),this.textureCount++}}},f.PixiShader.prototype.createGLTexture=function(a,b,c,d){a.bindTexture(a.TEXTURE_2D,d),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,c,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR_MIPMAP_LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.REPEAT),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.REPEAT),a.generateMipmap(a.TEXTURE_2D)},f.PixiShader.prototype.createGLTextureLinear=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)},f.PixiShader.prototype.createGLTextureNearestRepeat=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.REPEAT),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.REPEAT)},f.PixiShader.prototype.createGLTextureNearest=function(a,b,c){a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)},f.PixiShader.prototype.createAudioTexture=function(a,b){a.bindTexture(a.TEXTURE_2D,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),a.texImage2D(a.TEXTURE_2D,0,a.LUMINANCE,512,2,0,a.LUMINANCE,a.UNSIGNED_BYTE,null)},f.PixiShader.prototype.createKeyboardTexture=function(a,b){a.bindTexture(a.TEXTURE_2D,b),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),a.texImage2D(a.TEXTURE_2D,0,a.LUMINANCE,256,2,0,a.LUMINANCE,a.UNSIGNED_BYTE,null)},f.PixiShader.defaultVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","varying vec2 vTextureCoord;","varying float vColor;","const vec2 center = vec2(-1.0, 1.0);","void main(void) {","gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.StripShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying vec2 offsetVector;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"]},f.StripShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.uSampler=b.getUniformLocation(a,"uSampler"),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.aTextureCoord=b.getAttribLocation(a,"aTextureCoord"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.PrimitiveShader=function(){this.program,this.fragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],this.vertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);","v -= offsetVector.xyx;","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"]},f.PrimitiveShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),this.projectionVector=b.getUniformLocation(a,"projectionVector"),this.offsetVector=b.getUniformLocation(a,"offsetVector"),this.aVertexPosition=b.getAttribLocation(a,"aVertexPosition"),this.colorAttribute=b.getAttribLocation(a,"aColor"),this.translationMatrix=b.getUniformLocation(a,"translationMatrix"),this.alpha=b.getUniformLocation(a,"alpha"),this.program=a},f.WebGLGraphics=function(){},f.WebGLGraphics.renderGraphics=function(a,b){var c=f.gl;a._webGL||(a._webGL={points:[],indices:[],lastIndex:0,buffer:c.createBuffer(),indexBuffer:c.createBuffer()}),a.dirty&&(a.dirty=!1,a.clearDirty&&(a.clearDirty=!1,a._webGL.lastIndex=0,a._webGL.points=[],a._webGL.indices=[]),f.WebGLGraphics.updateGraphics(a)),f.activatePrimitiveShader();var d=f.mat3.clone(a.worldTransform);f.mat3.transpose(d),c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA),c.uniformMatrix3fv(f.primitiveShader.translationMatrix,!1,d),c.uniform2f(f.primitiveShader.projectionVector,b.x,-b.y),c.uniform2f(f.primitiveShader.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(f.primitiveShader.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.primitiveShader.aVertexPosition,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveShader.colorAttribute,4,c.FLOAT,!1,24,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),c.drawElements(c.TRIANGLE_STRIP,a._webGL.indices.length,c.UNSIGNED_SHORT,0),f.deactivatePrimitiveShader()},f.WebGLGraphics.updateGraphics=function(a){for(var b=a._webGL.lastIndex;b3&&f.WebGLGraphics.buildPoly(c,a._webGL),c.lineWidth>0&&f.WebGLGraphics.buildLine(c,a._webGL)):c.type==f.Graphics.RECT?f.WebGLGraphics.buildRectangle(c,a._webGL):(c.type==f.Graphics.CIRC||c.type==f.Graphics.ELIP)&&f.WebGLGraphics.buildCircle(c,a._webGL)}a._webGL.lastIndex=a.graphicsData.length;var d=f.gl;a._webGL.glPoints=new Float32Array(a._webGL.points),d.bindBuffer(d.ARRAY_BUFFER,a._webGL.buffer),d.bufferData(d.ARRAY_BUFFER,a._webGL.glPoints,d.STATIC_DRAW),a._webGL.glIndicies=new Uint16Array(a._webGL.indices),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),d.bufferData(d.ELEMENT_ARRAY_BUFFER,a._webGL.glIndicies,d.STATIC_DRAW)},f.WebGLGraphics.buildRectangle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3];if(a.fill){var j=d(a.fillColor),k=a.fillAlpha,l=j[0]*k,m=j[1]*k,n=j[2]*k,o=b.points,p=b.indices,q=o.length/6;o.push(e,g),o.push(l,m,n,k),o.push(e+h,g),o.push(l,m,n,k),o.push(e,g+i),o.push(l,m,n,k),o.push(e+h,g+i),o.push(l,m,n,k),p.push(q,q,q+1,q+2,q+3,q+3)}a.lineWidth&&(a.points=[e,g,e+h,g,e+h,g+i,e,g+i,e,g],f.WebGLGraphics.buildLine(a,b))},f.WebGLGraphics.buildCircle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3],j=40,k=2*Math.PI/j;if(a.fill){var l=d(a.fillColor),m=a.fillAlpha,n=l[0]*m,o=l[1]*m,p=l[2]*m,q=b.points,r=b.indices,s=q.length/6;r.push(s);for(var t=0;j+1>t;t++)q.push(e,g,n,o,p,m),q.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i,n,o,p,m),r.push(s++,s++);r.push(s-1)}if(a.lineWidth){a.points=[];for(var t=0;j+1>t;t++)a.points.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i);f.WebGLGraphics.buildLine(a,b)}},f.WebGLGraphics.buildLine=function(a,b){var c=a.points;if(0!=c.length){if(a.lineWidth%2)for(var e=0;ee;e++)k=c[2*(e-1)],l=c[2*(e-1)+1],m=c[2*e],n=c[2*e+1],o=c[2*(e+1)],p=c[2*(e+1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,s=-(n-p),t=m-o,E=Math.sqrt(s*s+t*t),s/=E,t/=E,s*=K,t*=K,w=-r+l-(-r+n),x=-q+m-(-q+k),y=(-q+k)*(-r+n)-(-q+m)*(-r+l),z=-t+p-(-t+n),A=-s+m-(-s+o),B=(-s+o)*(-t+n)-(-s+m)*(-t+p),C=w*A-z*x,Math.abs(C)<.1?(C+=10.1,F.push(m-q,n-r,N,O,P,M),F.push(m+q,n+r,N,O,P,M)):(px=(x*B-A*y)/C,py=(z*y-w*B)/C,D=(px-m)*(px-m)+(py-n)+(py-n),D>19600?(u=q-s,v=r-t,E=Math.sqrt(u*u+v*v),u/=E,v/=E,u*=K,v*=K,F.push(m-u,n-v),F.push(N,O,P,M),F.push(m+u,n+v),F.push(N,O,P,M),F.push(m-u,n-v),F.push(N,O,P,M),I++):(F.push(px,py),F.push(N,O,P,M),F.push(m-(px-m),n-(py-n)),F.push(N,O,P,M)));k=c[2*(H-2)],l=c[2*(H-2)+1],m=c[2*(H-1)],n=c[2*(H-1)+1],q=-(l-n),r=k-m,E=Math.sqrt(q*q+r*r),q/=E,r/=E,q*=K,r*=K,F.push(m-q,n-r),F.push(N,O,P,M),F.push(m+q,n+r),F.push(N,O,P,M),G.push(J);for(var e=0;I>e;e++)G.push(J++);G.push(J-1)}},f.WebGLGraphics.buildPoly=function(a,b){var c=a.points;if(!(c.length<6)){for(var e=b.points,g=b.indices,h=c.length/2,i=d(a.fillColor),j=a.fillAlpha,k=i[0]*j,l=i[1]*j,m=i[2]*j,n=f.PolyK.Triangulate(c),o=e.length/6,p=0;pp;p++)e.push(c[2*p],c[2*p+1],k,l,m,j)}},f._defaultFrame=new f.Rectangle(0,0,1,1),f.gl,f.WebGLRenderer=function(a,b,c,d,e){this.transparent=!!d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var g=this;this.view.addEventListener("webglcontextlost",function(a){g.handleContextLost(a)},!1),this.view.addEventListener("webglcontextrestored",function(a){g.handleContextRestored(a)},!1),this.batchs=[];var h={alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0};try{f.gl=this.gl=this.view.getContext("experimental-webgl",h)}catch(i){try{f.gl=this.gl=this.view.getContext("webgl",h)}catch(i){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}}f.initDefaultShaders();var j=this.gl;j.useProgram(f.defaultShader.program),f.WebGLRenderer.gl=j,this.batch=new f.WebGLBatch(j),j.disable(j.DEPTH_TEST),j.disable(j.CULL_FACE),j.enable(j.BLEND),j.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),f.offset=new f.Point(0,0),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new f.WebGLRenderGroup(this.gl,this.transparent)},f.WebGLRenderer.prototype.constructor=f.WebGLRenderer,f.WebGLRenderer.getBatch=function(){return 0==f._batchs.length?new f.WebGLBatch(f.WebGLRenderer.gl):f._batchs.pop()},f.WebGLRenderer.returnBatch=function(a){a.clean(),f._batchs.push(a)},f.WebGLRenderer.prototype.render=function(a){if(!this.contextLost){this.__stage!==a&&(this.__stage=a,this.stageRenderGroup.setRenderable(a)),f.WebGLRenderer.updateTextures(),f.visibleCount++,a.updateTransform();var b=this.gl;if(b.colorMask(!0,!0,!0,this.transparent),b.viewport(0,0,this.width,this.height),b.bindFramebuffer(b.FRAMEBUFFER,null),b.clearColor(a.backgroundColorSplit[0],a.backgroundColorSplit[1],a.backgroundColorSplit[2],!this.transparent),b.clear(b.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=a.backgroundColorSplit,f.projection.x=this.width/2,f.projection.y=-this.height/2,this.stageRenderGroup.render(f.projection),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0){for(var c=0;cc;c++){var d=6*c,e=4*c;this.indices[d+0]=e+0,this.indices[d+1]=e+1,this.indices[d+2]=e+2,this.indices[d+3]=e+0,this.indices[d+4]=e+2,this.indices[d+5]=e+3}a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,this.indices,a.STATIC_DRAW)},f.WebGLBatch.prototype.refresh=function(){this.gl;this.dynamicSizen;n++)renderable=this.batchs[n],renderable instanceof f.WebGLBatch?this.batchs[n].render():this.renderSpecial(renderable,b);endBatch instanceof f.WebGLBatch?endBatch.render(0,h+1):this.renderSpecial(endBatch,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){var c=a.vcount===f.visibleCount;a instanceof f.TilingSprite?c&&this.renderTilingSprite(a,b):a instanceof f.Strip?c&&this.renderStrip(a,b):a instanceof f.CustomRenderable?c&&a.renderWebGL(this,b):a instanceof f.Graphics?c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b):a instanceof f.FilterBlock&&this.handleFilterBlock(a,b)},flip=!1;var l=[],m=0;f.WebGLRenderGroup.prototype.handleFilterBlock=function(a,b){var c=f.gl;if(a.open)a.data instanceof Array?this.filterManager.pushFilter(a):(m++,l.push(a),c.enable(c.STENCIL_TEST),c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.INCR),f.WebGLGraphics.renderGraphics(a.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP));else if(a.data instanceof Array)this.filterManager.popFilter();else{var d=l.pop(a);d&&(c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,1),c.stencilOp(c.KEEP,c.KEEP,c.DECR),f.WebGLGraphics.renderGraphics(d.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,l.length),c.stencilOp(c.KEEP,c.KEEP,c.KEEP)),c.disable(c.STENCIL_TEST)}},f.WebGLRenderGroup.prototype.updateTexture=function(a){this.removeObject(a);for(var b=a.first;b!=this.root&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););this.insertObject(a,b,c)},f.WebGLRenderGroup.prototype.addFilterBlocks=function(a,b){a.__renderGroup=this,b.__renderGroup=this;for(var c=a;c!=this.root.first&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root.first&&(d=d._iPrev,!d.renderable||!d.__renderGroup););this.insertAfter(b,d)},f.WebGLRenderGroup.prototype.removeFilterBlocks=function(a,b){this.removeObject(a),this.removeObject(b)},f.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(a){a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a);for(var b=a.first;b!=this.root.first&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););var d=a.first,e=a.last._iNext;do d.__renderGroup=this,d.renderable&&(this.insertObject(d,b,c),b=d),d=d._iNext;while(d!=e)},f.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(a){if(a.__renderGroup==this){{a.last}do a.__renderGroup=null,a.renderable&&this.removeObject(a),a=a._iNext;while(a)}},f.WebGLRenderGroup.prototype.insertObject=function(a,b,c){var d=b,e=c;if(a instanceof f.Sprite){var g,h;if(d instanceof f.Sprite){if(g=d.batch,g&&g.texture==a.texture.baseTexture&&g.blendMode==a.blendMode)return g.insertAfter(a,d),void 0}else g=d;if(e)if(e instanceof f.Sprite){if(h=e.batch){if(h.texture==a.texture.baseTexture&&h.blendMode==a.blendMode)return h.insertBefore(a,e),void 0;if(h==g){var i=g.split(e),j=f.WebGLRenderer.getBatch(),k=this.batchs.indexOf(g);return j.init(a),this.batchs.splice(k+1,0,j,i),void 0}}}else h=e;var j=f.WebGLRenderer.getBatch();if(j.init(a),g){var k=this.batchs.indexOf(g);this.batchs.splice(k+1,0,j)}else this.batchs.push(j)}else a instanceof f.TilingSprite?this.initTilingSprite(a):a instanceof f.Strip&&this.initStrip(a),this.insertAfter(a,d)},f.WebGLRenderGroup.prototype.insertAfter=function(a,b){if(b instanceof f.Sprite){var c=b.batch;if(c)if(c.tail==b){var d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a)}else{var e=c.split(b.__next),d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a,e)}else this.batchs.push(a)}else{var d=this.batchs.indexOf(b);this.batchs.splice(d+1,0,a)}},f.WebGLRenderGroup.prototype.removeObject=function(a){var b;if(a instanceof f.Sprite){var c=a.batch;if(!c)return;c.remove(a),0==c.size&&(b=c)}else b=a;if(b){var d=this.batchs.indexOf(b);if(-1==d)return;if(0==d||d==this.batchs.length-1)return this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),void 0;if(this.batchs[d-1]instanceof f.WebGLBatch&&this.batchs[d+1]instanceof f.WebGLBatch&&this.batchs[d-1].texture==this.batchs[d+1].texture&&this.batchs[d-1].blendMode==this.batchs[d+1].blendMode)return this.batchs[d-1].merge(this.batchs[d+1]),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),f.WebGLRenderer.returnBatch(this.batchs[d+1]),this.batchs.splice(d,2),void 0;this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b)}},f.WebGLRenderGroup.prototype.initTilingSprite=function(a){var b=this.gl;a.verticies=new Float32Array([0,0,a.width,0,a.width,a.height,0,a.height]),a.uvs=new Float32Array([0,0,1,0,1,1,0,1]),a.colors=new Float32Array([1,1,1,1]),a.indices=new Uint16Array([0,1,3,2]),a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW),a.texture.baseTexture._glTexture?(b.bindTexture(b.TEXTURE_2D,a.texture.baseTexture._glTexture),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.REPEAT),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.REPEAT),a.texture.baseTexture._powerOf2=!0):a.texture.baseTexture._powerOf2=!0},f.WebGLRenderGroup.prototype.renderStrip=function(a,b){var c=this.gl;f.activateStripShader();var d=f.stripShader,e=(d.program,f.mat3.clone(a.worldTransform));f.mat3.transpose(e),c.uniformMatrix3fv(d.translationMatrix,!1,e),c.uniform2f(d.projectionVector,b.x,b.y),c.uniform2f(d.offsetVector,-f.offset.x,-f.offset.y),c.uniform1f(d.alpha,a.worldAlpha),a.dirty?(a.dirty=!1,c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferData(c.ARRAY_BUFFER,a.verticies,c.STATIC_DRAW),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferData(c.ARRAY_BUFFER,a.uvs,c.STATIC_DRAW),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.bufferData(c.ARRAY_BUFFER,a.colors,c.STATIC_DRAW),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,a.indices,c.STATIC_DRAW)):(c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.verticies),c.vertexAttribPointer(d.aVertexPosition,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.aTextureCoord,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer)),c.drawElements(c.TRIANGLE_STRIP,a.indices.length,c.UNSIGNED_SHORT,0),f.deactivateStripShader() +},f.WebGLRenderGroup.prototype.renderTilingSprite=function(a,b){var c=this.gl,d=(f.shaderProgram,a.tilePosition),e=a.tileScale,g=d.x/a.texture.baseTexture.width,h=d.y/a.texture.baseTexture.height,i=a.width/a.texture.baseTexture.width/e.x,j=a.height/a.texture.baseTexture.height/e.y;a.uvs[0]=0-g,a.uvs[1]=0-h,a.uvs[2]=1*i-g,a.uvs[3]=0-h,a.uvs[4]=1*i-g,a.uvs[5]=1*j-h,a.uvs[6]=0-g,a.uvs[7]=1*j-h,c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.uvs),this.renderStrip(a,b)},f.WebGLRenderGroup.prototype.initStrip=function(a){{var b=this.gl;this.shaderProgram}a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW)},f.WebGLFilterManager=function(a){this.transparent=a,this.filterStack=[],this.texturePool=[],this.offsetX=0,this.offsetY=0,this.initShaderBuffers()},f.WebGLFilterManager.prototype.begin=function(a,b){this.width=2*a.x,this.height=2*-a.y,this.buffer=b},f.WebGLFilterManager.prototype.pushFilter=function(a){var b=f.gl;this.filterStack.push(a);var c=a.filterPasses[0];this.offsetX+=a.target.filterArea.x,this.offsetY+=a.target.filterArea.y;var d=this.texturePool.pop();d||(d=new f.FilterTexture(this.width,this.height)),b.bindTexture(b.TEXTURE_2D,d.texture),this.getBounds(a.target);var e=a.target.filterArea,g=c.padding;e.x-=g,e.y-=g,e.width+=2*g,e.height+=2*g,e.x<0&&(e.x=0),e.width>this.width&&(e.width=this.width),e.y<0&&(e.y=0),e.height>this.height&&(e.height=this.height),b.bindFramebuffer(b.FRAMEBUFFER,d.frameBuffer),b.viewport(0,0,e.width,e.height),f.projection.x=e.width/2,f.projection.y=-e.height/2,f.offset.x=-e.x,f.offset.y=-e.y,b.uniform2f(f.defaultShader.projectionVector,e.width/2,-e.height/2),b.uniform2f(f.defaultShader.offsetVector,-e.x,-e.y),b.colorMask(!0,!0,!0,!0),b.clearColor(0,0,0,0),b.clear(b.COLOR_BUFFER_BIT),a._glFilterTexture=d},f.WebGLFilterManager.prototype.popFilter=function(){var a=f.gl,b=this.filterStack.pop(),c=b.target.filterArea,d=b._glFilterTexture;if(b.filterPasses.length>1){a.viewport(0,0,c.width,c.height),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer),this.vertexArray[0]=0,this.vertexArray[1]=c.height,this.vertexArray[2]=c.width,this.vertexArray[3]=c.height,this.vertexArray[4]=0,this.vertexArray[5]=0,this.vertexArray[6]=c.width,this.vertexArray[7]=0,a.bufferSubData(a.ARRAY_BUFFER,0,this.vertexArray),a.bindBuffer(a.ARRAY_BUFFER,this.uvBuffer),this.uvArray[2]=c.width/this.width,this.uvArray[5]=c.height/this.height,this.uvArray[6]=c.width/this.width,this.uvArray[7]=c.height/this.height,a.bufferSubData(a.ARRAY_BUFFER,0,this.uvArray);var e=d,g=this.texturePool.pop();g||(g=new f.FilterTexture(this.width,this.height)),a.bindFramebuffer(a.FRAMEBUFFER,g.frameBuffer),a.clear(a.COLOR_BUFFER_BIT),a.disable(a.BLEND);for(var h=0;hs?s:E,E=E>t?t:E,E=E>u?u:E,E=E>v?v:E,F=F>w?w:F,F=F>x?x:F,F=F>y?y:F,F=F>z?z:F,C=s>C?s:C,C=t>C?t:C,C=u>C?u:C,C=v>C?v:C,D=w>D?w:D,D=x>D?x:D,D=y>D?y:D,D=z>D?z:D),l=!1,A=A._iNext}while(A!=B);a.filterArea.x=E,a.filterArea.y=F,a.filterArea.width=C-E,a.filterArea.height=D-F},f.FilterTexture=function(a,b){var c=f.gl;this.frameBuffer=c.createFramebuffer(),this.texture=c.createTexture(),c.bindTexture(c.TEXTURE_2D,this.texture),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.bindFramebuffer(c.FRAMEBUFFER,this.framebuffer),c.bindFramebuffer(c.FRAMEBUFFER,this.frameBuffer),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,this.texture,0),this.resize(a,b)},f.FilterTexture.prototype.resize=function(a,b){this.width=a,this.height=b;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.texture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,a,b,0,c.RGBA,c.UNSIGNED_BYTE,null)},f.CanvasRenderer=function(a,b,c,d){this.transparent=d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},f.CanvasRenderer.prototype.constructor=f.CanvasRenderer,f.CanvasRenderer.prototype.render=function(a){f.texturesToUpdate=[],f.texturesToDestroy=[],f.visibleCount++,a.updateTransform(),this.view.style.backgroundColor==a.backgroundColorString||this.transparent||(this.view.style.backgroundColor=a.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(a),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0&&(f.Texture.frameUpdates=[])},f.CanvasRenderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.view.width=a,this.view.height=b},f.CanvasRenderer.prototype.renderDisplayObject=function(a){var b,c=this.context;c.globalCompositeOperation="source-over";var d=a.last._iNext;a=a.first;do if(b=a.worldTransform,a.visible)if(a.renderable){if(a instanceof f.Sprite){var e=a.texture.frame;e&&e.width&&e.height&&(c.globalAlpha=a.worldAlpha,c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),c.drawImage(a.texture.baseTexture.source,e.x,e.y,e.width,e.height,a.anchor.x*-e.width,a.anchor.y*-e.height,e.width,e.height))}else if(a instanceof f.Strip)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderStrip(a);else if(a instanceof f.TilingSprite)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderTilingSprite(a);else if(a instanceof f.CustomRenderable)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),a.renderCanvas(this);else if(a instanceof f.Graphics)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),f.CanvasGraphics.renderGraphics(a,c);else if(a instanceof f.FilterBlock&&a.data instanceof f.Graphics){var g=a.data;if(a.open){c.save();var h=g.alpha,i=g.worldTransform;c.setTransform(i[0],i[3],i[1],i[4],i[2],i[5]),g.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(g,c),c.clip(),g.worldAlpha=h}else c.restore()}a=a._iNext}else a=a._iNext;else a=a.last._iNext;while(a!=d)},f.CanvasRenderer.prototype.renderStripFlat=function(a){var b=this.context,c=a.verticies,d=(a.uvs,c.length/2);this.count++,b.beginPath();for(var e=1;d-2>e;e++){var f=2*e,g=c[f],h=c[f+2],i=c[f+4],j=c[f+1],k=c[f+3],l=c[f+5];b.moveTo(g,j),b.lineTo(h,k),b.lineTo(i,l)}b.fillStyle="#FF0000",b.fill(),b.closePath()},f.CanvasRenderer.prototype.renderTilingSprite=function(a){var b=this.context;b.globalAlpha=a.worldAlpha,a.__tilePattern||(a.__tilePattern=b.createPattern(a.texture.baseTexture.source,"repeat")),b.beginPath();var c=a.tilePosition,d=a.tileScale;b.scale(d.x,d.y),b.translate(c.x,c.y),b.fillStyle=a.__tilePattern,b.fillRect(-c.x,-c.y,a.width/d.x,a.height/d.y),b.scale(1/d.x,1/d.y),b.translate(-c.x,-c.y),b.closePath()},f.CanvasRenderer.prototype.renderStrip=function(a){var b=this.context,c=a.verticies,d=a.uvs,e=c.length/2;this.count++;for(var f=1;e-2>f;f++){var g=2*f,h=c[g],i=c[g+2],j=c[g+4],k=c[g+1],l=c[g+3],m=c[g+5],n=d[g]*a.texture.width,o=d[g+2]*a.texture.width,p=d[g+4]*a.texture.width,q=d[g+1]*a.texture.height,r=d[g+3]*a.texture.height,s=d[g+5]*a.texture.height;b.save(),b.beginPath(),b.moveTo(h,k),b.lineTo(i,l),b.lineTo(j,m),b.closePath(),b.clip();var t=n*r+q*p+o*s-r*p-q*o-n*s,u=h*r+q*j+i*s-r*j-q*i-h*s,v=n*i+h*p+o*j-i*p-h*o-n*j,w=n*r*j+q*i*p+h*o*s-h*r*p-q*o*j-n*i*s,x=k*r+q*m+l*s-r*m-q*l-k*s,y=n*l+k*p+o*m-l*p-k*o-n*m,z=n*r*m+q*l*p+k*o*s-k*r*p-q*o*m-n*l*s;b.transform(u/t,x/t,v/t,y/t,w/t,z/t),b.drawImage(a.texture.baseTexture.source,0,0),b.restore()}},f.CanvasGraphics=function(){},f.CanvasGraphics.renderGraphics=function(a,b){for(var c=a.worldAlpha,d=0;d1&&(c=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var d=0;1>d;d++){var e=a.graphicsData[d],g=e.points;if(e.type==f.Graphics.POLY){b.beginPath(),b.moveTo(g[0],g[1]);for(var h=1;hb?b:d,e=b+m>e?b+m:e,g=g>c?b:g,h=c+n>h?c+n:h}else if(k===f.Graphics.CIRC||k===f.Graphics.ELIP){b=a.x,c=a.y;var o=a.radius+l/2;d=d>b-o?b-o:d,e=b+o>e?b+o:e,g=g>c-o?c-o:g,h=c+o>h?c+o:h}else for(var p=0;pb-l?b-l:d,e=b+l>e?b+l:e,g=g>c-l?c-l:g,h=c+l>h?c+l:h}this.bounds=new f.Rectangle(d,g,e-d,h-g)}},f.Graphics.POLY=0,f.Graphics.RECT=1,f.Graphics.CIRC=2,f.Graphics.ELIP=3,f.Strip=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.blendMode=f.blendModes.NORMAL;try{this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.verticies=new Float32Array([0,0,0,0,0,0,0,0,0]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3])}catch(d){this.uvs=[0,1,1,1,1,0,0,1],this.verticies=[0,0,0,0,0,0,0,0,0],this.colors=[1,1,1,1],this.indices=[0,1,2,3]}this.width=b,this.height=c,a.baseTexture.hasLoaded?(this.width=this.texture.frame.width,this.height=this.texture.frame.height,this.updateFrame=!0):(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Strip.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Strip.prototype.constructor=f.Strip,f.Strip.prototype.setTexture=function(a){this.texture=a,this.width=a.frame.width,this.height=a.frame.height,this.updateFrame=!0},f.Strip.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Rope=function(a,b){f.Strip.call(this,a),this.points=b;try{this.verticies=new Float32Array(4*b.length),this.uvs=new Float32Array(4*b.length),this.colors=new Float32Array(2*b.length),this.indices=new Uint16Array(2*b.length)}catch(c){this.verticies=verticies,this.uvs=uvs,this.colors=colors,this.indices=indices}this.refresh()},f.Rope.prototype=Object.create(f.Strip.prototype),f.Rope.prototype.constructor=f.Rope,f.Rope.prototype.refresh=function(){var a=this.points;if(!(a.length<1)){var b=this.uvs,c=this.indices,d=this.colors,e=a[0],f=a[0];this.count-=.2,b[0]=0,b[1]=1,b[2]=0,b[3]=1,d[0]=1,d[1]=1,c[0]=0,c[1]=1;for(var g=a.length,h=1;g>h;h++){var f=a[h],i=4*h,j=h/(g-1);h%2?(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1):(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1),i=2*h,d[i]=1,d[i+1]=1,i=2*h,c[i]=i,c[i+1]=i+1,e=f}}},f.Rope.prototype.updateTransform=function(){var a=this.points;if(!(a.length<1)){var b,c=this.verticies,d=a[0],e={x:0,y:0},g=a[0];this.count-=.2,c[0]=g.x+e.x,c[1]=g.y+e.y,c[2]=g.x-e.x,c[3]=g.y-e.y;for(var h=a.length,i=1;h>i;i++){var g=a[i],j=4*i;b=i1&&(k=1);var l=Math.sqrt(e.x*e.x+e.y*e.y),m=this.texture.height/2;e.x/=l,e.y/=l,e.x*=m,e.y*=m,c[j]=g.x+e.x,c[j+1]=g.y+e.y,c[j+2]=g.x-e.x,c[j+3]=g.y-e.y,d=g}f.DisplayObjectContainer.prototype.updateTransform.call(this)}},f.Rope.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.width=b,this.height=c,this.tileScale=new f.Point(1,1),this.tilePosition=new f.Point(0,0),this.renderable=!0,this.blendMode=f.blendModes.NORMAL},f.TilingSprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.TilingSprite.prototype.constructor=f.TilingSprite,f.TilingSprite.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Spine=function(a){if(f.DisplayObjectContainer.call(this),this.spineData=f.AnimCache[a],!this.spineData)throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+a);this.skeleton=new n.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new n.AnimationStateData(this.spineData),this.state=new n.AnimationState(this.stateData),this.slotContainers=[];for(var b=0,c=this.skeleton.drawOrder.length;c>b;b++){var d=this.skeleton.drawOrder[b],e=d.attachment,g=new f.DisplayObjectContainer;if(this.slotContainers.push(g),this.addChild(g),e instanceof n.RegionAttachment){var h=e.rendererObject.name,i=this.createSprite(d,e.rendererObject);d.currentSprite=i,d.currentSpriteName=h,g.addChild(i)}}},f.Spine.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Spine.prototype.constructor=f.Spine,f.Spine.prototype.updateTransform=function(){this.lastTime=this.lastTime||Date.now();var a=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.state.update(a),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var b=this.skeleton.drawOrder,c=0,d=b.length;d>c;c++){var e=b[c],g=e.attachment,h=this.slotContainers[c];if(g instanceof n.RegionAttachment){if(g.rendererObject&&(!e.currentSpriteName||e.currentSpriteName!=g.name)){var i=g.rendererObject.name;if(void 0!==e.currentSprite&&(e.currentSprite.visible=!1),e.sprites=e.sprites||{},void 0!==e.sprites[i])e.sprites[i].visible=!0;else{var j=this.createSprite(e,g.rendererObject);h.addChild(j)}e.currentSprite=e.sprites[i],e.currentSpriteName=i}h.visible=!0;var k=e.bone;h.position.x=k.worldX+g.x*k.m00+g.y*k.m01,h.position.y=k.worldY+g.x*k.m10+g.y*k.m11,h.scale.x=k.worldScaleX,h.scale.y=k.worldScaleY,h.rotation=-(e.bone.worldRotation*Math.PI/180)}else h.visible=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.Spine.prototype.createSprite=function(a,b){var c=f.TextureCache[b.name]?b.name:b.name+".png",d=new f.Sprite(f.Texture.fromFrame(c));return d.scale=b.scale,d.rotation=b.rotation,d.anchor.x=d.anchor.y=.5,a.sprites=a.sprites||{},a.sprites[b.name]=d,d};var n={};n.BoneData=function(a,b){this.name=a,this.parent=b},n.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},n.SlotData=function(a,b){this.name=a,this.boneData=b},n.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},n.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},n.Bone.yDown=!1,n.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(a,b){var c=this.parent;null!=c?(this.worldX=this.x*c.m00+this.y*c.m01+c.worldX,this.worldY=this.x*c.m10+this.y*c.m11+c.worldY,this.worldScaleX=c.worldScaleX*this.scaleX,this.worldScaleY=c.worldScaleY*this.scaleY,this.worldRotation=c.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var d=this.worldRotation*Math.PI/180,e=Math.cos(d),f=Math.sin(d);this.m00=e*this.worldScaleX,this.m10=f*this.worldScaleX,this.m01=-f*this.worldScaleY,this.m11=e*this.worldScaleY,a&&(this.m00=-this.m00,this.m01=-this.m01),b&&(this.m10=-this.m10,this.m11=-this.m11),n.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var a=this.data;this.x=a.x,this.y=a.y,this.rotation=a.rotation,this.scaleX=a.scaleX,this.scaleY=a.scaleY}},n.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},n.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(a){this.attachment=a,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(a){this._attachmentTime=this.skeleton.time-a},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var a=this.data;this.r=a.r,this.g=a.g,this.b=a.b,this.a=a.a;for(var b=this.skeleton.data.slots,c=0,d=b.length;d>c;c++)if(b[c]==a){this.setAttachment(a.attachmentName?this.skeleton.getAttachmentBySlotIndex(c,a.attachmentName):null);break}}},n.Skin=function(a){this.name=a,this.attachments={}},n.Skin.prototype={addAttachment:function(a,b,c){this.attachments[a+":"+b]=c},getAttachment:function(a,b){return this.attachments[a+":"+b]},_attachAll:function(a,b){for(var c in b.attachments){var d=c.indexOf(":"),e=parseInt(c.substring(0,d)),f=c.substring(d+1),g=a.slots[e];if(g.attachment&&g.attachment.name==f){var h=this.getAttachment(e,f);h&&g.setAttachment(h)}}}},n.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},n.Animation.prototype={apply:function(a,b,c){c&&0!=this.duration&&(b%=this.duration);for(var d=this.timelines,e=0,f=d.length;f>e;e++)d[e].apply(a,b,1)},mix:function(a,b,c,d){c&&0!=this.duration&&(b%=this.duration);for(var e=this.timelines,f=0,g=e.length;g>f;f++)e[f].apply(a,b,d)}},n.binarySearch=function(a,b,c){var d=0,e=Math.floor(a.length/c)-2;if(0==e)return c;for(var f=e>>>1;;){if(a[(f+1)*c]<=b?d=f+1:e=f,d==e)return(d+1)*c;f=d+e>>>1}},n.linearSearch=function(a,b,c){for(var d=0,e=a.length-c;e>=d;d+=c)if(a[d]>b)return d;return-1},n.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},n.Curves.prototype={setLinear:function(a){this.curves[6*a]=0},setStepped:function(a){this.curves[6*a]=-1},setCurve:function(a,b,c,d,e){var f=.1,g=f*f,h=g*f,i=3*f,j=3*g,k=6*g,l=6*h,m=2*-b+d,n=2*-c+e,o=3*(b-d)+1,p=3*(c-e)+1,q=6*a,r=this.curves;r[q]=b*i+m*j+o*h,r[q+1]=c*i+n*j+p*h,r[q+2]=m*k+o*l,r[q+3]=n*k+p*l,r[q+4]=o*l,r[q+5]=p*l},getCurvePercent:function(a,b){b=0>b?0:b>1?1:b;var c=6*a,d=this.curves,e=d[c];if(!e)return b;if(-1==e)return 0;for(var f=d[c+1],g=d[c+2],h=d[c+3],i=d[c+4],j=d[c+5],k=e,l=f,m=8;;){if(k>=b){var n=k-e,o=l-f;return o+(l-o)*(b-n)/(k-n)}if(0==m)break;m--,e+=g,f+=h,g+=i,h+=j,k+=e,l+=f}return l+(1-l)*(b-k)/(1-k)}},n.RotateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=2*a},n.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(a,b,c){a*=2,this.frames[a]=b,this.frames[a+1]=c},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-2]){for(var f=e.data.rotation+d[d.length-1]-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;return e.rotation+=f*c,void 0}var g=n.binarySearch(d,b,2),h=d[g-1],i=d[g],j=1-(b-i)/(d[g-2]-i);j=this.curves.getCurvePercent(g/2-1,j);for(var f=d[g+1]-h;f>180;)f-=360;for(;-180>f;)f+=360;for(f=e.data.rotation+(h+f*j)-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;e.rotation+=f*c}}},n.TranslateTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.x+=(e.data.x+d[d.length-2]-e.x)*c,e.y+=(e.data.y+d[d.length-1]-e.y)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.x+=(e.data.x+g+(d[f+1]-g)*j-e.x)*c,e.y+=(e.data.y+h+(d[f+2]-h)*j-e.y)*c}}},n.ScaleTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=3*a},n.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.scaleX+=(e.data.scaleX-1+d[d.length-2]-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+d[d.length-1]-e.scaleY)*c,void 0;var f=n.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.scaleX+=(e.data.scaleX-1+g+(d[f+1]-g)*j-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+h+(d[f+2]-h)*j-e.scaleY)*c}}},n.ColorTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=5*a},n.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(c,d){c*=5,this.frames[c]=d,this.frames[c+1]=r,this.frames[c+2]=g,this.frames[c+3]=b,this.frames[c+4]=a},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-5]){var f=d.length-1;return e.r=d[f-3],e.g=d[f-2],e.b=d[f-1],e.a=d[f],void 0}var g=n.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],l=d[g],m=1-(b-l)/(d[g-5]-l);m=this.curves.getCurvePercent(g/5-1,m);var o=h+(d[g+1]-h)*m,p=i+(d[g+2]-i)*m,q=j+(d[g+3]-j)*m,r=k+(d[g+4]-k)*m;1>c?(e.r+=(o-e.r)*c,e.g+=(p-e.g)*c,e.b+=(q-e.b)*c,e.a+=(r-e.a)*c):(e.r=o,e.g=p,e.b=q,e.a=r)}}},n.AttachmentTimeline=function(a){this.curves=new n.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},n.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(a,b,c){this.frames[a]=b,this.attachmentNames[a]=c},apply:function(a,b){var c=this.frames;if(!(b=c[c.length-1]?c.length-1:n.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},n.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},n.SkeletonData.prototype={defaultSkin:null,findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return slot[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSkin:function(a){for(var b=this.skins,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findAnimation:function(a){for(var b=this.animations,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null}},n.Skeleton=function(a){this.data=a,this.bones=[];for(var b=0,c=a.bones.length;c>b;b++){var d=a.bones[b],e=d.parent?this.bones[a.bones.indexOf(d.parent)]:null;this.bones.push(new n.Bone(d,e))}this.slots=[],this.drawOrder=[];for(var b=0,c=a.slots.length;c>b;b++){var f=a.slots[b],g=this.bones[a.bones.indexOf(f.boneData)],h=new n.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},n.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var a=this.flipX,b=this.flipY,c=this.bones,d=0,e=c.length;e>d;d++)c[d].updateWorldTransform(a,b)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var a=this.bones,b=0,c=a.length;c>b;b++)a[b].setToSetupPose()},setSlotsToSetupPose:function(){for(var a=this.slots,b=0,c=a.length;c>b;b++)a[b].setToSetupPose(b)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},setSkinByName:function(a){var b=this.data.findSkin(a); +if(!b)throw"Skin not found: "+a;this.setSkin(b)},setSkin:function(a){this.skin&&a&&a._attachAll(this,this.skin),this.skin=a},getAttachmentBySlotName:function(a,b){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(a),b)},getAttachmentBySlotIndex:function(a,b){if(this.skin){var c=this.skin.getAttachment(a,b);if(c)return c}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(a,b):null},setAttachment:function(a,b){for(var c=this.slots,d=0,e=c.size;e>d;d++){var f=c[d];if(f.data.name==a){var g=null;if(b&&(g=this.getAttachment(d,b),null==g))throw"Attachment not found: "+b+", for slot: "+a;return f.setAttachment(g),void 0}}throw"Slot not found: "+a},update:function(a){time+=a}},n.AttachmentType={region:0},n.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},n.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(a,b,c,d,e){var f=this.uvs;e?(f[2]=a,f[3]=d,f[4]=a,f[5]=b,f[6]=c,f[7]=b,f[0]=c,f[1]=d):(f[0]=a,f[1]=d,f[2]=a,f[3]=b,f[4]=c,f[5]=b,f[6]=c,f[7]=d)},updateOffset:function(){var a=this.width/this.regionOriginalWidth*this.scaleX,b=this.height/this.regionOriginalHeight*this.scaleY,c=-this.width/2*this.scaleX+this.regionOffsetX*a,d=-this.height/2*this.scaleY+this.regionOffsetY*b,e=c+this.regionWidth*a,f=d+this.regionHeight*b,g=this.rotation*Math.PI/180,h=Math.cos(g),i=Math.sin(g),j=c*h+this.x,k=c*i,l=d*h+this.y,m=d*i,n=e*h+this.x,o=e*i,p=f*h+this.y,q=f*i,r=this.offset;r[0]=j-m,r[1]=l+k,r[2]=j-q,r[3]=p+k,r[4]=n-q,r[5]=p+o,r[6]=n-m,r[7]=l+o},computeVertices:function(a,b,c,d){a+=c.worldX,b+=c.worldY;var e=c.m00,f=c.m01,g=c.m10,h=c.m11,i=this.offset;d[0]=i[0]*e+i[1]*f+a,d[1]=i[0]*g+i[1]*h+b,d[2]=i[2]*e+i[3]*f+a,d[3]=i[2]*g+i[3]*h+b,d[4]=i[4]*e+i[5]*f+a,d[5]=i[4]*g+i[5]*h+b,d[6]=i[6]*e+i[7]*f+a,d[7]=i[6]*g+i[7]*h+b}},n.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},n.AnimationStateData.prototype={defaultMix:0,setMixByName:function(a,b,c){var d=this.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;var e=this.skeletonData.findAnimation(b);if(!e)throw"Animation not found: "+b;this.setMix(d,e,c)},setMix:function(a,b,c){this.animationToMixTime[a.name+":"+b.name]=c},getMix:function(a,b){var c=this.animationToMixTime[a.name+":"+b.name];return c?c:this.defaultMix}},n.AnimationState=function(a){this.data=a,this.queue=[]},n.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(a){if(this.currentTime+=a,this.previousTime+=a,this.mixTime+=a,this.queue.length>0){var b=this.queue[0];this.currentTime>=b.delay&&(this._setAnimation(b.animation,b.loop),this.queue.shift())}},apply:function(a){if(this.current)if(this.previous){this.previous.apply(a,this.previousTime,this.previousLoop);var b=this.mixTime/this.mixDuration;b>=1&&(b=1,this.previous=null),this.current.mix(a,this.currentTime,this.currentLoop,b)}else this.current.apply(a,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(a,b){this.previous=null,a&&this.current&&(this.mixDuration=this.data.getMix(this.current,a),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=a,this.currentLoop=b,this.currentTime=0},setAnimationByName:function(a,b){var c=this.data.skeletonData.findAnimation(a);if(!c)throw"Animation not found: "+a;this.setAnimation(c,b)},setAnimation:function(a,b){this.queue.length=0,this._setAnimation(a,b)},addAnimationByName:function(a,b,c){var d=this.data.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;this.addAnimation(d,b,c)},addAnimation:function(a,b,c){var d={};if(d.animation=a,d.loop=b,!c||0>=c){var e=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;c=null!=e?e.duration-this.data.getMix(e,a)+(c||0):0}d.delay=c,this.queue.push(d)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},n.SkeletonJson=function(a){this.attachmentLoader=a},n.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new n.SkeletonData,c=a.bones,d=0,e=c.length;e>d;d++){var f=c[d],g=null;if(f.parent&&(g=b.findBone(f.parent),!g))throw"Parent bone not found: "+f.parent;var h=new n.BoneData(f.name,g);h.length=(f.length||0)*this.scale,h.x=(f.x||0)*this.scale,h.y=(f.y||0)*this.scale,h.rotation=f.rotation||0,h.scaleX=f.scaleX||1,h.scaleY=f.scaleY||1,b.bones.push(h)}for(var i=a.slots,d=0,e=i.length;e>d;d++){var j=i[d],h=b.findBone(j.bone);if(!h)throw"Slot bone not found: "+j.bone;var k=new n.SlotData(j.name,h),l=j.color;l&&(k.r=n.SkeletonJson.toColor(l,0),k.g=n.SkeletonJson.toColor(l,1),k.b=n.SkeletonJson.toColor(l,2),k.a=n.SkeletonJson.toColor(l,3)),k.attachmentName=j.attachment,b.slots.push(k)}var m=a.skins;for(var o in m)if(m.hasOwnProperty(o)){var p=m[o],q=new n.Skin(o);for(var r in p)if(p.hasOwnProperty(r)){var s=b.findSlotIndex(r),t=p[r];for(var u in t)if(t.hasOwnProperty(u)){var v=this.readAttachment(q,u,t[u]);null!=v&&q.addAttachment(s,u,v)}}b.skins.push(q),"default"==q.name&&(b.defaultSkin=q)}var w=a.animations;for(var x in w)w.hasOwnProperty(x)&&this.readAnimation(x,w[x],b);return b},readAttachment:function(a,b,c){b=c.name||b;var d=n.AttachmentType[c.type||"region"];if(d==n.AttachmentType.region){var e=new n.RegionAttachment;return e.x=(c.x||0)*this.scale,e.y=(c.y||0)*this.scale,e.scaleX=c.scaleX||1,e.scaleY=c.scaleY||1,e.rotation=c.rotation||0,e.width=(c.width||32)*this.scale,e.height=(c.height||32)*this.scale,e.updateOffset(),e.rendererObject={},e.rendererObject.name=b,e.rendererObject.scale={},e.rendererObject.scale.x=e.scaleX,e.rendererObject.scale.y=e.scaleY,e.rendererObject.rotation=-e.rotation*Math.PI/180,e}throw"Unknown attachment type: "+d},readAnimation:function(a,b,c){var d=[],e=0,f=b.bones;for(var g in f)if(f.hasOwnProperty(g)){var h=c.findBoneIndex(g);if(-1==h)throw"Bone not found: "+g;var i=f[g];for(var j in i)if(i.hasOwnProperty(j)){var k=i[j];if("rotate"==j){var l=new n.RotateTimeline(k.length);l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m,q.time,q.angle),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[2*l.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var l,r=1;"scale"==j?l=new n.ScaleTimeline(k.length):(l=new n.TranslateTimeline(k.length),r=this.scale),l.boneIndex=h;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;l.setFrame(m,q.time,s,t),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[3*l.getFrameCount()-3])}}}var u=b.slots;for(var v in u)if(u.hasOwnProperty(v)){var w=u[v],x=c.findSlotIndex(v);for(var j in w)if(w.hasOwnProperty(j)){var k=w[j];if("color"==j){var l=new n.ColorTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=n.SkeletonJson.toColor(y,0),A=n.SkeletonJson.toColor(y,1),B=n.SkeletonJson.toColor(y,2),C=n.SkeletonJson.toColor(y,3);l.setFrame(m,q.time,z,A,B,C),n.SkeletonJson.readCurve(l,m,q),m++}d.push(l),e=Math.max(e,l.frames[5*l.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var l=new n.AttachmentTimeline(k.length);l.slotIndex=x;for(var m=0,o=0,p=k.length;p>o;o++){var q=k[o];l.setFrame(m++,q.time,q.name)}d.push(l),e=Math.max(e,l.frames[l.getFrameCount()-1])}}}c.animations.push(new n.Animation(a,d,e))}},n.SkeletonJson.readCurve=function(a,b,c){var d=c.curve;d&&("stepped"==d?a.curves.setStepped(b):d instanceof Array&&a.curves.setCurve(b,d[0],d[1],d[2],d[3]))},n.SkeletonJson.toColor=function(a,b){if(8!=a.length)throw"Color hexidecimal length must be 8, recieved: "+a;return parseInt(a.substring(2*b,2),16)/255},n.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new n.AtlasReader(a),d=[];d.length=4;for(var e=null;;){var f=c.readLine();if(null==f)break;if(f=c.trim(f),0==f.length)e=null;else if(e){var g=new n.AtlasRegion;g.name=f,g.page=e,g.rotate="true"==c.readValue(),c.readTuple(d);var h=parseInt(d[0]),i=parseInt(d[1]);c.readTuple(d);var j=parseInt(d[0]),k=parseInt(d[1]);g.u=h/e.width,g.v=i/e.height,g.rotate?(g.u2=(h+k)/e.width,g.v2=(i+j)/e.height):(g.u2=(h+j)/e.width,g.v2=(i+k)/e.height),g.x=h,g.y=i,g.width=Math.abs(j),g.height=Math.abs(k),4==c.readTuple(d)&&(g.splits=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],4==c.readTuple(d)&&(g.pads=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],c.readTuple(d))),g.originalWidth=parseInt(d[0]),g.originalHeight=parseInt(d[1]),c.readTuple(d),g.offsetX=parseInt(d[0]),g.offsetY=parseInt(d[1]),g.index=parseInt(c.readValue()),this.regions.push(g)}else{e=new n.AtlasPage,e.name=f,e.format=n.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=n.Atlas.TextureFilter[d[0]],e.magFilter=n.Atlas.TextureFilter[d[1]];var l=c.readValue();e.uWrap=n.Atlas.TextureWrap.clampToEdge,e.vWrap=n.Atlas.TextureWrap.clampToEdge,"x"==l?e.uWrap=n.Atlas.TextureWrap.repeat:"y"==l?e.vWrap=n.Atlas.TextureWrap.repeat:"xy"==l&&(e.uWrap=e.vWrap=n.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},n.Atlas.prototype={findRegion:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},dispose:function(){for(var a=this.pages,b=0,c=a.length;c>b;b++)this.textureLoader.unload(a[b].rendererObject)},updateUVs:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++){var e=b[c];e.page==a&&(e.u=e.x/a.width,e.v=e.y/a.height,e.rotate?(e.u2=(e.x+e.height)/a.width,e.v2=(e.y+e.width)/a.height):(e.u2=(e.x+e.width)/a.width,e.v2=(e.y+e.height)/a.height))}}},n.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},n.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},n.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},n.AtlasPage=function(){},n.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},n.AtlasRegion=function(){},n.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},n.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},n.AtlasReader.prototype={index:0,trim:function(a){return a.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var a=this.readLine(),b=a.indexOf(":");if(-1==b)throw"Invalid line: "+a;return this.trim(a.substring(b+1))},readTuple:function(a){var b=this.readLine(),c=b.indexOf(":");if(-1==c)throw"Invalid line: "+b;for(var d=0,e=c+1;3>d;d++){var f=b.indexOf(",",e);if(-1==f){if(0==d)throw"Invalid line: "+b;break}a[d]=this.trim(b.substr(e,f-e)),e=f+1}return a[d]=this.trim(b.substring(e)),d+1}},n.AtlasAttachmentLoader=function(a){this.atlas=a},n.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case n.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new n.RegionAttachment(c);return e.rendererObject=d,e.setUVs(d.u,d.v,d.u2,d.v2,d.rotate),e.regionOffsetX=d.offsetX,e.regionOffsetY=d.offsetY,e.regionWidth=d.width,e.regionHeight=d.height,e.regionOriginalWidth=d.originalWidth,e.regionOriginalHeight=d.originalHeight,e}throw"Unknown attachment type: "+b}},f.AnimCache={},n.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this),this.renderable=!0},f.CustomRenderable.prototype=Object.create(f.DisplayObject.prototype),f.CustomRenderable.prototype.constructor=f.CustomRenderable,f.CustomRenderable.prototype.renderCanvas=function(){},f.CustomRenderable.prototype.initWebGL=function(){},f.CustomRenderable.prototype.renderWebGL=function(){},f.BaseTextureCache={},f.texturesToUpdate=[],f.texturesToDestroy=[],f.BaseTexture=function(a){if(f.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=a,a){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);else{var b=this;this.source.onload=function(){b.hasLoaded=!0,b.width=b.source.width,b.height=b.source.height,f.texturesToUpdate.push(b),b.dispatchEvent({type:"loaded",content:b})}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);this._powerOf2=!1}},f.BaseTexture.prototype.constructor=f.BaseTexture,f.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,f.texturesToDestroy.push(this)},f.BaseTexture.fromImage=function(a,b){var c=f.BaseTextureCache[a];if(!c){var d=new Image;b&&(d.crossOrigin=""),d.src=a,c=new f.BaseTexture(d),f.BaseTextureCache[a]=c}return c},f.TextureCache={},f.FrameCache={},f.Texture=function(a,b){if(f.EventTarget.call(this),b||(this.noFrame=!0,b=new f.Rectangle(0,0,1,1)),a instanceof f.Texture&&(a=a.baseTexture),this.baseTexture=a,this.frame=b,this.trim=new f.Point,this.scope=this,a.hasLoaded)this.noFrame&&(b=new f.Rectangle(0,0,a.width,a.height)),this.setFrame(b);else{var c=this;a.addEventListener("loaded",function(){c.onBaseTextureLoaded()})}},f.Texture.prototype.constructor=f.Texture,f.Texture.prototype.onBaseTextureLoaded=function(){var a=this.baseTexture;a.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new f.Rectangle(0,0,a.width,a.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},f.Texture.prototype.destroy=function(a){a&&this.baseTexture.destroy()},f.Texture.prototype.setFrame=function(a){if(this.frame=a,this.width=a.width,this.height=a.height,a.x+a.width>this.baseTexture.width||a.y+a.height>this.baseTexture.height)throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,f.Texture.frameUpdates.push(this)},f.Texture.fromImage=function(a,b){var c=f.TextureCache[a];return c||(c=new f.Texture(f.BaseTexture.fromImage(a,b)),f.TextureCache[a]=c),c},f.Texture.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache "+this);return b},f.Texture.fromCanvas=function(a){var b=new f.BaseTexture(a);return new f.Texture(b)},f.Texture.addTextureToCache=function(a,b){f.TextureCache[b]=a},f.Texture.removeTextureFromCache=function(a){var b=f.TextureCache[a];return f.TextureCache[a]=null,b},f.Texture.frameUpdates=[],f.RenderTexture=function(a,b){f.EventTarget.call(this),this.width=a||100,this.height=b||100,this.indetityMatrix=f.mat3.create(),this.frame=new f.Rectangle(0,0,this.width,this.height),f.gl?this.initWebGL():this.initCanvas()},f.RenderTexture.prototype=Object.create(f.Texture.prototype),f.RenderTexture.prototype.constructor=f.RenderTexture,f.RenderTexture.prototype.initWebGL=function(){var a=f.gl;this.glFramebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new f.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.baseTexture._glTexture),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,this.width,this.height,0,a.RGBA,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new f.Point(this.width/2,-this.height/2),this.render=this.renderWebGL},f.RenderTexture.prototype.resize=function(a,b){if(this.width=a,this.height=b,f.gl){this.projection.x=this.width/2,this.projection.y=-this.height/2;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.baseTexture._glTexture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,this.width,this.height,0,c.RGBA,c.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height)},f.RenderTexture.prototype.initCanvas=function(){this.renderer=new f.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new f.BaseTexture(this.renderer.view),this.frame=new f.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},f.RenderTexture.prototype.renderWebGL=function(a,b,c){var d=f.gl;d.colorMask(!0,!0,!0,!0),d.viewport(0,0,this.width,this.height),d.bindFramebuffer(d.FRAMEBUFFER,this.glFramebuffer),c&&(d.clearColor(0,0,0,0),d.clear(d.COLOR_BUFFER_BIT));var e=a.children,g=a.worldTransform;a.worldTransform=f.mat3.create(),a.worldTransform[4]=-1,a.worldTransform[5]=-2*this.projection.y,b&&(a.worldTransform[2]=b.x,a.worldTransform[5]-=b.y),f.visibleCount++,a.vcount=f.visibleCount;for(var h=0,i=e.length;i>h;h++)e[h].updateTransform();var j=a.__renderGroup;j?a==j.root?j.render(this.projection,this.glFramebuffer):j.renderSpecific(a,this.projection,this.glFramebuffer):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection,this.glFramebuffer)),a.worldTransform=g},f.RenderTexture.prototype.renderCanvas=function(a,b,c){var d=a.children;a.worldTransform=f.mat3.create(),b&&(a.worldTransform[2]=b.x,a.worldTransform[5]=b.y);for(var e=0,g=d.length;g>e;e++)d[e].updateTransform();c&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(a),this.renderer.context.setTransform(1,0,0,1,0,0)},f.AssetLoader=function(a,b){f.EventTarget.call(this),this.assetURLs=a,this.crossorigin=b,this.loadersByType={jpg:f.ImageLoader,jpeg:f.ImageLoader,png:f.ImageLoader,gif:f.ImageLoader,json:f.JsonLoader,anim:f.SpineLoader,xml:f.BitmapFontLoader,fnt:f.BitmapFontLoader}},f.AssetLoader.prototype.constructor=f.AssetLoader,f.AssetLoader.prototype.load=function(){var a=this;this.loadCount=this.assetURLs.length;for(var b=0;bh;h++)for(var i=0;d>i;i++,g++){var j=new f.Texture(this.texture,{x:i*a,y:h*b,width:a,height:b});this.frames.push(j),c&&(f.TextureCache[c+"-"+g]=j)}if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var k=this;this.texture.baseTexture.addEventListener("loaded",function(){k.onLoaded()})}},f.BitmapFontLoader=function(a,b){f.EventTarget.call(this),this.url=a,this.crossorigin=b,this.baseUrl=a.replace(/[^\/]*$/,""),this.texture=null},f.BitmapFontLoader.prototype.constructor=f.BitmapFontLoader,f.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var a=this;this.ajaxRequest.onreadystatechange=function(){a.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},f.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var a=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,b=new f.ImageLoader(a,this.crossorigin);this.texture=b.texture.baseTexture;var c={},d=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],e=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];c.font=d.attributes.getNamedItem("face").nodeValue,c.size=parseInt(d.attributes.getNamedItem("size").nodeValue,10),c.lineHeight=parseInt(e.attributes.getNamedItem("lineHeight").nodeValue,10),c.chars={};for(var g=this.ajaxRequest.responseXML.getElementsByTagName("char"),h=0;h - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +