diff --git a/app/Lib/Vendor/Pixi/pixi.dev.js b/app/Lib/Vendor/Pixi/pixi.dev.js index fb753ff..cc5c47f 100755 --- a/app/Lib/Vendor/Pixi/pixi.dev.js +++ b/app/Lib/Vendor/Pixi/pixi.dev.js @@ -1,12 +1,12 @@ /** * @license - * Pixi.JS - v1.3.0 + * pixi.js - v1.4.2 * Copyright (c) 2012, Mat Groves * http://goodboydigital.com/ * - * Compiled: 2013-10-17 + * Compiled: 2014-01-15 * - * Pixi.JS is licensed under the MIT License. + * pixi.js is licensed under the MIT License. * http://www.opensource.org/licenses/mit-license.php */ /** @@ -15,7 +15,7 @@ (function(){ - var root = this; + var root = this; /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -26,6 +26,9 @@ */ var PIXI = PIXI || {}; +PIXI.WEBGL_RENDERER = 0; +PIXI.CANVAS_RENDERER = 1; + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -34,26 +37,26 @@ var PIXI = PIXI || {}; * 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 + * @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; -} + /** + * @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 @@ -63,8 +66,8 @@ PIXI.Point = function(x, y) */ PIXI.Point.prototype.clone = function() { - return new PIXI.Point(this.x, this.y); -} + return new PIXI.Point(this.x, this.y); +}; // constructor PIXI.Point.prototype.constructor = PIXI.Point; @@ -78,42 +81,42 @@ PIXI.Point.prototype.constructor = PIXI.Point; * 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 + * @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 wisth of this 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; -} + /** + * @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 @@ -123,8 +126,8 @@ PIXI.Rectangle = function(x, y, width, height) */ PIXI.Rectangle.prototype.clone = function() { - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -} + 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 @@ -139,19 +142,19 @@ 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; - } - } + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; - return false; -} + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; // constructor PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; @@ -165,7 +168,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @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 arugments passed can be + * 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. @@ -188,8 +191,8 @@ PIXI.Polygon = function(points) points = p; } - this.points = points; -} + this.points = points; +}; /** * Creates a clone of this polygon @@ -199,13 +202,13 @@ PIXI.Polygon = function(points) */ PIXI.Polygon.prototype.clone = function() { - var points = []; - for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + intersect = ((yi > 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 */ @@ -256,7 +259,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -270,7 +273,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.radius = radius || 0; -} +}; /** * Creates a clone of this Circle instance @@ -281,7 +284,7 @@ PIXI.Circle = function(x, y, radius) 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 @@ -304,8 +307,9 @@ PIXI.Circle.prototype.contains = function(x, y) dy *= dy; return (dx + dy <= r2); -} +}; +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +324,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @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 height of this ellipse - * @param height {Number} The overall width 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) { @@ -331,28 +335,28 @@ PIXI.Ellipse = function(x, y, width, height) * @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 @@ -363,7 +367,7 @@ PIXI.Ellipse = function(x, y, width, height) 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 @@ -387,18 +391,18 @@ PIXI.Ellipse.prototype.contains = function(x, y) normy *= normy; return (normx + normy < 0.25); -} +}; -PIXI.Ellipse.getBounds = function() +PIXI.Ellipse.prototype.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! @@ -415,112 +419,112 @@ PIXI.mat3 = {}; PIXI.mat3.create = function() { - var matrix = new PIXI.Matrix(9); + 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; -} + 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; -} + 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); + 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; -} + 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; -PIXI.mat3.multiply = function (mat, mat2, dest) + 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; -} + 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); + 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; -} + 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]; -PIXI.mat3.transpose = function (mat, dest) + 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 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]; @@ -544,34 +548,34 @@ PIXI.mat3.transpose = function (mat, dest) dest[7] = mat[5]; dest[8] = mat[8]; return dest; -} +}; -PIXI.mat3.toMat4 = function (mat, 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; -} + 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; +}; ///// @@ -579,83 +583,83 @@ PIXI.mat3.toMat4 = function (mat, dest) PIXI.mat4.create = function() { - var matrix = new PIXI.Matrix(16); + 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; -} + 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; -PIXI.mat4.transpose = function (mat, dest) + 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; -} + // 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]; -PIXI.mat4.multiply = function (mat, mat2, dest) + 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]; + 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; @@ -689,7 +693,9 @@ PIXI.mat4.multiply = function (mat, mat2, dest) dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; return dest; -} +}; + +PIXI.identityMatrix = PIXI.mat3.create(); /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -703,234 +709,255 @@ PIXI.mat4.multiply = function (mat, mat2, dest) */ PIXI.DisplayObject = function() { - this.last = this; - this.first = this; + 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 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 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 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 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 opacity of the object. - * - * @property alpha - * @type Number - */ - this.alpha = 1; + /** + * The visibility of the object. + * + * @property visible + * @type Boolean + */ + this.visible = true; - /** - * 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 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; - /** - * 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; - /** - * 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 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 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] 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] Whether or not the object is interactive, do not toggle directly! use the `interactive` property - * - * @property _interactive - * @type Boolean - * @readOnly - * @private - */ - this._interactive = false; + /** + * This is the curser that will be used when the mouse is over this object. To enable this the element must have interaction = true and buttonMode = true + * + * @property defaultCursor + * @type String + * + */ + this.defaultCursor = 'pointer'; - /** - * [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 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(); + /** + * [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] 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; + /** + * [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; - - /* - * 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} - */ + // chach that puppy! + this._sr = 0; + this._cr = 1; - /* - * TOUCH Callbacks - */ + this.filterArea = new PIXI.Rectangle(0,0,1,1); - /** - * 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} - */ + /** + * + * + * + */ + this._bounds = new PIXI.Rectangle(0, 0, 1, 1); + this._currentBounds = null; + this._mask = null; - /** - * A callback that is used when the user releases a touch over the displayObject - * @method touchend - * @param interactionData {InteractionData} - */ + /* + * MOUSE Callbacks + */ - /** - * 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} - */ -} + /** + * 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; @@ -945,8 +972,8 @@ PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; */ PIXI.DisplayObject.prototype.setInteractive = function(interactive) { - this.interactive = interactive; -} + this.interactive = interactive; +}; /** * Indicates if the sprite will have touch and mouse interactivity. It is false by default @@ -960,11 +987,32 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { 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; + this._interactive = value; + + // TODO more to be done here.. + // need to sort out a re-crawl! + if(this.stage)this.stage.dirty = true; + } +}); + +/** + * [read-only] Indicates if the sprite is globaly visible. + * + * @property worldVisible + * @type Boolean + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'worldVisible', { + get: function() { + var item = this; + + do + { + if(!item.visible)return false; + item = item.parent; + } + while(item); + + return true; } }); @@ -981,171 +1029,46 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { return this._mask; }, set: function(value) { - + + if(this._mask)this._mask.isMask = false; this._mask = value; - - if(value) - { - this.addFilter(value) - } - else - { - this.removeFilter(); - } + if(this._mask)this._mask.isMask = true; } }); -/* - * Adds a filter to this displayObject - * - * @method addFilter - * @param mask {Graphics} the graphics object to use as a filter - * @private +/** + * 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 */ -PIXI.DisplayObject.prototype.addFilter = function(mask) -{ - if(this.filter)return; - this.filter = true; - - // insert a filter block.. - var start = new PIXI.FilterBlock(); - var end = new PIXI.FilterBlock(); - - start.mask = mask; - end.mask = mask; - - start.first = start.last = this; - end.first = end.last = this; - - start.open = true; - - /* - * 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); - } - - mask.renderable = false; - -} +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { -/* - * Removes the filter to this displayObject - * - * @method removeFilter - * @private - */ -PIXI.DisplayObject.prototype.removeFilter = function() -{ - if(!this.filter)return; - this.filter = false; - - // modify the list.. - var startBlock = this.first; - - 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 = this.last; - - 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; - } - - var mask = startBlock.mask - mask.renderable = true; - - // if webGL... - if(this.__renderGroup) - { - this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); - } -} + if(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]); + } + } + + // TODO change this as it is legacy + this._filterBlock = {target:this, filterPasses:passes}; + } + + this._filters = value; + } +}); /* * Updates the object transform for rendering @@ -1155,28 +1078,28 @@ PIXI.DisplayObject.prototype.removeFilter = function() */ 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; - + // 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], @@ -1184,9 +1107,9 @@ PIXI.DisplayObject.prototype.updateTransform = function() b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; - localTransform[2] = a02 - localTransform[5] = a12 - + 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; @@ -1195,15 +1118,54 @@ PIXI.DisplayObject.prototype.updateTransform = function() 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; + // 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; +}; + +PIXI.DisplayObject.prototype.getBounds = function() +{ + return PIXI.EmptyRectangle; +}; + +PIXI.DisplayObject.prototype.getLocalBounds = function() +{ + var matrixCache = this.worldTransform; + + this.worldTransform = PIXI.identityMatrix; + + this.updateTransform(); + + var bounds = this.getBounds(); + + this.worldTransform = matrixCache; + + return bounds; +}; + +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; + +PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) +{ + // OVERWRITE; + // this line is just here to pass jshinting :) + renderSession = renderSession; +}; + +PIXI.DisplayObject.prototype._renderCanvas = function(renderSession) +{ + // OVERWRITE; + // this line is just here to pass jshinting :) + renderSession = renderSession; +}; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); -} -PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1213,39 +1175,65 @@ PIXI.visibleCount = 0; * 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 + * @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 = []; -} + 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; -//TODO make visible a getter setter +/** + * The width of the displayObjectContainer, setting this will actually modify the scale to acheive the value set + * + * @property width + * @type Number + */ + /* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { +Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'width', { get: function() { - return this._visible; + return this.scale.x * this.getLocalBounds().width; }, set: function(value) { - this._visible = value; - + this.scale.x = value / (this.getLocalBounds().width/this.scale.x); + this._width = value; } -});*/ +}); +*/ + +/** + * The height of the displayObjectContainer, setting this will actually modify the scale to acheive the value set + * + * @property height + * @type Number + */ + + /* +Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'height', { + get: function() { + return this.scale.y * this.getLocalBounds().height; + }, + set: function(value) { + this.scale.y = value / (this.getLocalBounds().height/this.scale.y); + this._height = value; + } +}); +*/ /** * Adds a child to the container. @@ -1255,85 +1243,22 @@ Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { */ PIXI.DisplayObjectContainer.prototype.addChild = function(child) { - if(child.parent != undefined) - { - - //// COULD BE THIS??? - child.parent.removeChild(child); - // return; - } + if(child.parent && child !== this) + { + //// 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.filter) - { - previousObject = this.last._iPrev; - } - else - { - previousObject = this.last; - } + child.parent = this; - 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; + this.children.push(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); - } - -} + // update the stage refference.. + + if(this.stage)child.setStageReference(this.stage); + +}; /** * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown @@ -1344,83 +1269,24 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) */ 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; + if(index >= 0 && index <= this.children.length) + { + if(child.parent) + { + child.parent.removeChild(child); + } - 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); - } -} + child.parent = this; + + this.children.splice(index, 0, child); + + if(this.stage)child.setStageReference(this.stage); + } + else + { + throw new Error(child + ' The index '+ index +' supplied is out of bounds ' + this.children.length); + } +}; /** * [NYI] Swaps the depth of 2 displayObjects @@ -1432,44 +1298,21 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) */ 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); - }*/ -} + if(child === child2) { + return; + } + + var index1 = this.children.indexOf(child); + var index2 = this.children.indexOf(child2); + + if(index1 < 0 || index2 < 0) { + throw new Error('swapChildren: Both the supplied DisplayObjects must be a child of the caller.'); + } + + this.children[index1] = child2; + this.children[index2] = child; + +}; /** * Returns the Child at the specified index @@ -1479,15 +1322,15 @@ PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) */ 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); - } -} + if(index >= 0 && index < this.children.length) + { + return this.children[index]; + } + else + { + throw new Error('The supplied DisplayObjects must be a child of the caller ' + this); + } +}; /** * Removes a child from the container. @@ -1497,63 +1340,20 @@ PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) */ 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); - } -} + var index = this.children.indexOf( child ); + if ( index !== -1 ) + { + // update the stage reference.. + if(this.stage)child.removeStageReference(); + + 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 @@ -1563,29 +1363,173 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - if(!this.visible)return; - - PIXI.DisplayObject.prototype.updateTransform.call( this ); - - for(var i=0,j=this.children.length; i childMaxX ? maxX : childMaxX; + maxY = maxY > childMaxY ? maxY : childMaxY; + } + + var bounds = this._bounds; + + bounds.x = minX; + bounds.y = minY; + bounds.width = maxX - minX; + bounds.height = maxY - minY; + + // TODO: store a refferance so that if this function gets called again in the render cycle we do not have to recacalculate + //this._currentBounds = bounds; + + return bounds; +}; + +PIXI.DisplayObjectContainer.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; + + for(var i=0,j=this.children.length; i 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; + + var bounds = this._bounds; + + bounds.x = minX; + bounds.width = maxX - minX; + + bounds.y = minY; + bounds.height = maxY - minY; + + // store a refferance so that if this function gets called again in the render cycle we do not have to recacalculate + this._currentBounds = bounds; + + return bounds; +}; + + +PIXI.Sprite.prototype._renderWebGL = function(renderSession) +{ + // if the sprite is not visible or the alpha is 0 then no need to render this element + if(this.visible === false || this.alpha === 0)return; + + var i,j; + + // do a quick check to see if this element has a mask or a filter. + if(this._mask || this._filters) + { + var spriteBatch = renderSession.spriteBatch; + + if(this._mask) + { + spriteBatch.stop(); + renderSession.maskManager.pushMask(this.mask, renderSession); + spriteBatch.start(); + } + + if(this._filters) + { + spriteBatch.flush(); + renderSession.filterManager.pushFilter(this._filterBlock); + } + + // add this sprite to the batch + spriteBatch.render(this); + + // now loop through the children and make sure they get rendered + for(i=0,j=this.children.length; i= this.textures.length) - { - this.gotoAndStop(this.textures.length - 1); - if(this.onComplete) - { - this.onComplete(); - } - } -} + 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(mask) +PIXI.FilterBlock = function() { - this.graphics = mask - this.visible = true; - this.renderable = true; -} - + 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" + * 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.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"); + 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; }; @@ -1976,10 +2184,10 @@ PIXI.Text.prototype.constructor = PIXI.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.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 @@ -1987,10 +2195,10 @@ PIXI.Text.prototype.constructor = PIXI.Text; 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.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; @@ -1999,15 +2207,16 @@ PIXI.Text.prototype.setStyle = function(style) }; /** - * Set the copy for the text object. To split a line you can use "\n" + * Set the copy for the text object. To split a line you can use '\n' * - * @methos setText + * @method setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { - this.text = text.toString() || " "; + this.text = text.toString() || ' '; this.dirty = true; + }; /** @@ -2018,66 +2227,68 @@ PIXI.Sprite.prototype.setText = function(text) */ 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); + this.context.font = this.style.font; - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); + var outputText = this.text; - //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; + // word wrap + // preserve original text + if(this.style.wordWrap)outputText = this.wordWrap(this.text); - //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; + //split text into lines + var lines = outputText.split(/(?:\r\n|\r|\n)/); - this.context.textBaseline = "top"; + //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; - //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; - } + //calculate text height + var lineHeight = this.determineFontHeight('font: ' + this.style.font + ';') + this.style.strokeThickness; + this.canvas.height = lineHeight * lines.length; - if(this.style.stroke && this.style.strokeThickness) - { - this.context.strokeText(lines[i], linePosition.x, linePosition.y); - } + if(navigator.isCocoonJS) this.context.clearRect(0,0,this.canvas.width,this.canvas.height); + + //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); + } + } - if(this.style.fill) - { - this.context.fillText(lines[i], linePosition.x, linePosition.y); - } - } - this.updateTexture(); }; @@ -2093,11 +2304,22 @@ PIXI.Text.prototype.updateTexture = function() 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._width = this.canvas.width; this._height = this.canvas.height; - - PIXI.texturesToUpdate.push(this.texture.baseTexture); + + this.requiresUpdate = true; +}; + +PIXI.Text.prototype._renderWebGL = function(renderSession) +{ + if(this.requiresUpdate) + { + this.requiresUpdate = false; + PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } + + PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); }; /** @@ -2108,13 +2330,13 @@ PIXI.Text.prototype.updateTexture = function() */ PIXI.Text.prototype.updateTransform = function() { - if(this.dirty) - { - this.updateText(); - this.dirty = false; - } - - PIXI.Sprite.prototype.updateTransform.call(this); + if(this.dirty) + { + this.updateText(); + this.dirty = false; + } + + PIXI.Sprite.prototype.updateTransform.call(this); }; /* @@ -2125,32 +2347,33 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +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; + // 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; }; /** - * A Text Object will apply wordwrap + * 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} @@ -2158,49 +2381,38 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) */ PIXI.Text.prototype.wordWrap = function(text) { - // search good wrap position - var searchWrapPos = function(ctx, text, start, end, wrapWidth) - { - var p = Math.floor((end-start) / 2) + start; - if(p == start) { - return 1; - } - - if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) - { - if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) - { - return p; - } - else - { - return arguments.callee(ctx, text, p, end, wrapWidth); - } - } - else - { - return arguments.callee(ctx, text, start, p, wrapWidth); - } - }; - - var lineWrap = function(ctx, text, wrapWidth) - { - if(ctx.measureText(text).width <= wrapWidth || text.length < 1) - { - return text; - } - var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); - return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); - }; - - var result = ""; - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) - { - result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; - } - - return result; + // 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; }; /** @@ -2211,11 +2423,11 @@ PIXI.Text.prototype.wordWrap = function(text) */ PIXI.Text.prototype.destroy = function(destroyTexture) { - if(destroyTexture) - { - this.texture.destroy(); - } - + if(destroyTexture) + { + this.texture.destroy(); + } + }; PIXI.Text.heightCache = {}; @@ -2225,8 +2437,8 @@ PIXI.Text.heightCache = {}; */ /** - * 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 + * 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. * @@ -2235,8 +2447,8 @@ PIXI.Text.heightCache = {}; * @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") + * @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) { @@ -2245,8 +2457,7 @@ PIXI.BitmapText = function(text, style) this.setText(text); this.setStyle(style); this.updateText(); - this.dirty = false - + this.dirty = false; }; // constructor @@ -2261,7 +2472,7 @@ PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; */ PIXI.BitmapText.prototype.setText = function(text) { - this.text = text || " "; + this.text = text || ' '; this.dirty = true; }; @@ -2270,16 +2481,16 @@ PIXI.BitmapText.prototype.setText = function(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") + * @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"; + style.align = style.align || 'left'; this.style = style; - var font = style.font.split(" "); + 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; @@ -2316,13 +2527,13 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; if(prevCharCode && charData[prevCharCode]) { - pos.x += charData.kerning[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; @@ -2337,11 +2548,11 @@ PIXI.BitmapText.prototype.updateText = function() for(i = 0; i <= line; i++) { var alignOffset = 0; - if(this.style.align == "right") + if(this.style.align === 'right') { alignOffset = maxLineWidth - lineWidths[i]; } - else if(this.style.align == "center") + else if(this.style.align === 'center') { alignOffset = (maxLineWidth - lineWidths[i]) / 2; } @@ -2350,14 +2561,14 @@ PIXI.BitmapText.prototype.updateText = function() for(i = 0; i < chars.length; i++) { - var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); + 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.width = maxLineWidth * scale; this.height = (pos.y + data.lineHeight) * scale; }; @@ -2369,8 +2580,8 @@ PIXI.BitmapText.prototype.updateText = function() */ PIXI.BitmapText.prototype.updateTransform = function() { - if(this.dirty) - { + if(this.dirty) + { while(this.children.length > 0) { this.removeChild(this.getChildAt(0)); @@ -2378,9 +2589,9 @@ PIXI.BitmapText.prototype.updateTransform = function() this.updateText(); this.dirty = false; - } - - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; PIXI.BitmapText.fonts = {}; @@ -2389,9 +2600,7 @@ 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. * @@ -2401,46 +2610,55 @@ PIXI.BitmapText.fonts = {}; */ PIXI.InteractionManager = function(stage) { - /** - * a refference to the stage - * - * @property stage - * @type Stage - */ - this.stage = 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(); + /** + * 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 = {}; + /** + * 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(); - - // helpers - this.tempPoint = new PIXI.Point(); - //this.tempMatrix = mat3.create(); + this.mouseoverEnabled = true; - this.mouseoverEnabled = true; + //tiny little interactiveData pool! + this.pool = []; - //tiny little interactiveData pool! - this.pool = []; + this.interactiveItems = []; + this.interactionDOMElement = null; - this.interactiveItems = []; - - - this.last = 0; -} + //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; + + this.currentCursor = 'inherit'; +}; // constructor PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; @@ -2455,39 +2673,39 @@ PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; */ 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); + var children = displayObject.children; + var length = children.length; - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, child); - } - } - else - { - child.__iParent = null; + /// make an interaction tree... {item.__interactiveParent} + for (var i = length-1; i >= 0; i--) + { + var child = children[i]; - if(child.children.length > 0) - { - this.collectInteractiveSprite(child, iParent); - } - } -// } - } -} +// 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 @@ -2498,26 +2716,66 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { - if (window.navigator.msPointerEnabled) - { - // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" - - // DO some window specific touch! - } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseOut.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); -} + 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 @@ -2527,85 +2785,92 @@ PIXI.InteractionManager.prototype.setTarget = function(target) */ 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.target.view.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.target.view.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; - } - } - } - - // ---> - } -} + 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; + // + + var i = 0; + + // ok.. so mouse events?? + // yes for now :) + // OPTIMSE - how often to check?? + if(this.dirty) + { + this.dirty = false; + + var len = this.interactiveItems.length; + + for (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; + + // return; + + for (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.currentCursor = item.defaultCursor; + + 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; + } + } + } + // ---> + } + + + if(this.currentCursor !== this.interactionDOMElement.style.cursor) + { + this.interactionDOMElement.style.cursor = this.currentCursor; + } +}; /** * Is called when the mouse moves accross the renderer element @@ -2616,28 +2881,26 @@ PIXI.InteractionManager.prototype.update = function() */ 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.target.view.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); - } - } -} + 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; + + 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 @@ -2648,61 +2911,57 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ 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; - } - } - } -} + 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; + + // 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) +PIXI.InteractionManager.prototype.onMouseOut = function() { - var length = this.interactiveItems.length; - - this.target.view.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; - } - } -} + var length = this.interactiveItems.length; + + this.currentCursor = 'inherit'; + + 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 @@ -2713,48 +2972,45 @@ PIXI.InteractionManager.prototype.onMouseOut = function(event) */ 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; - } - } -} + this.mouse.originalEvent = event || window.event; //IE uses window.event + + 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 @@ -2766,68 +3022,70 @@ PIXI.InteractionManager.prototype.onMouseUp = function(event) */ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { - var global = interactionData.global; - - if(item.vcount !== PIXI.visibleCount)return false; + var global = interactionData.global; - 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; + if( !item.worldVisible )return false; - 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; + // temp fix for if the element is in a non visible + + 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; - 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; - } - } - } + interactionData.target = item; - 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; - } - } + //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 false; -} + 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 @@ -2838,27 +3096,34 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - var rect = this.target.view.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); - } -} + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + var touchData; + var i = 0; + + for (i = 0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + 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); + if(navigator.isCocoonJS) { + touchData.global.x = touchEvent.clientX; + touchData.global.y = touchEvent.clientY; + } + } + + var length = this.interactiveItems.length; + for (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 @@ -2869,45 +3134,49 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - var rect = this.target.view.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; - } - } - } - } -} + 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); + if(navigator.isCocoonJS) { + touchData.global.x = touchEvent.clientX; + touchData.global.y = touchEvent.clientY; + } + + 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 @@ -2918,67 +3187,73 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - //this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.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; - } -} + //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); + if(navigator.isCocoonJS) { + touchData.global.x = touchEvent.clientX; + touchData.global.y = touchEvent.clientY; + } + + 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 @@ -2988,33 +3263,33 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) */ 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(); + /** + * This point stores the global coords of where the touch/mouse event happened + * + * @property global + * @type Point + */ + this.global = new PIXI.Point(); - /** - * The target Sprite that was interacted with - * - * @property target - * @type Sprite - */ - this.target; + // this is here for legacy... but will remove + this.local = new PIXI.Point(); - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @property originalEvent - * @type Event - */ - this.originalEvent; -} + /** + * The target Sprite that was interacted with + * + * @property target + * @type Sprite + */ + this.target = null; + + /** + * When passed to an event handler, this will be the original DOM Event that was captured + * + * @property originalEvent + * @type Event + */ + this.originalEvent = null; +}; /** * This will return the local coords of the specified displayObject for this InteractionData @@ -3025,17 +3300,17 @@ PIXI.InteractionData = function() */ 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], + 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) -} + // 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; @@ -3051,65 +3326,72 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @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 - * @param interactive {Boolean} enable / disable interaction (default is false) + * like: 0xFFFFFF for white */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { - PIXI.DisplayObjectContainer.call( this ); + 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(); + /** + * [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 = interactive; + /** + * 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); + /** + * 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; + /** + * 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; - //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); - //optimize hit detection a bit - this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); - - this.setBackgroundColor(backgroundColor); - this.worldVisible = true; -} + this.setBackgroundColor(backgroundColor); +}; // 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 * @@ -3118,40 +3400,38 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; */ 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]; -} +PIXI.hex2rgb = function(hex) { + return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +}; + + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*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; - }; - })(); +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) { + if (proto) F.prototype = proto; + if (!(this instanceof F)) return new F(); + })(target.prototype); + + return bound; + }; + })(); } /** @@ -3250,60 +3537,86 @@ if (typeof Function.prototype.bind != 'function') { * @class AjaxRequest * @constructor */ -var AjaxRequest = PIXI.AjaxRequest = function() +PIXI.AjaxRequest = function AjaxRequest() { - var activexmodes = ["Msxml2.XMLHTTP", "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 - } - } -} + // console.log(r, b, c, d) + return (Math.floor((r)*63) << 18) | (Math.floor((g)*63) << 12) | (Math.floor((b)*63) << 6);// | (Math.floor((a)*63)) + // i = i | (Math.floor((a)*63)); + // return i; + // var r = (i / 262144.0 ) / 64; + // var g = (i / 4096.0)%64 / 64; + // var b = (i / 64.0)%64 / 64; + // var a = (i)%64 / 64; + + // console.log(r, g, b, a); + // return i; +}; +*/ +/* +PIXI.packColorRGB = function(r, g, b)//r, g, b, a) +{ + return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); +}; +PIXI.unpackColorRGB = function(r, g, b)//r, g, b, a) +{ + return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); +}; +*/ +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +}; + +// this function is taken from Starling Framework as its pretty neat ;) +PIXI.getNextPowerOfTwo = function(number) +{ + if (number > 0 && (number & (number - 1)) === 0) // see: http://goo.gl/D9kPj + return number; + else + { + var result = 1; + while (result < number) result <<= 1; + return result; + } +}; @@ -3317,55 +3630,66 @@ PIXI.runList = function(item) * * @class EventTarget * @example - * function MyEmitter() { - * PIXI.EventTarget.call(this); //mixes in event target stuff - * } + * function MyEmitter() { + * PIXI.EventTarget.call(this); //mixes in event target stuff + * } * - * var em = new MyEmitter(); - * em.emit({ type: 'eventName', data: 'some data' }); + * 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 ) { + var listeners = {}; - listeners[ type ] = []; - - } + this.addEventListener = this.on = function ( type, listener ) { - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - listeners[ type ].push( 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 ); + + } + + }; + + this.removeAllEventListeners = function( type ) { + var a = listeners[type]; + if (a) + a.length = 0; }; - - this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - - listeners[ event.type ][ listener ]( event ); - - } - - }; - - this.removeEventListener = this.off = function ( type, listener ) { - - var index = listeners[ type ].indexOf( listener ); - - if ( index !== - 1 ) { - - listeners[ type ].splice( index, 1 ); - - } - - }; - }; /** @@ -3384,65 +3708,71 @@ PIXI.EventTarget = function () { * @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; + if(!width)width = 800; + if(!height)height = 600; - // BORROWED from Mr Doob (mrdoob.com) - var webgl = ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(); - - // TEMP FIX - 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); - } + // 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; + } + } )(); - return new PIXI.CanvasRenderer(width, height, view, transparent); + // used to detect ie 11 - no longer required + /* if(webgl) + { + var ie = (navigator.userAgent.toLowerCase().indexOf('trident') !== -1); + webgl = !ie; + } + */ + + + 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 + PolyK library + url: http://polyk.ivank.net + Released under MIT licence. - 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: + Copyright (c) 2012 Ivan Kuckir - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. + 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 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. + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. - This is an amazing lib! - - slightly modified by mat groves (matgroves.com); + 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 = {}; @@ -3456,69 +3786,76 @@ PIXI.PolyK = {}; */ 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> 1; + if(n < 3) return []; + + var tgs = []; + var avl = []; + for(var i = 0; i < n; i++) avl.push(i); + + i = 0; + var al = n; + while(al > 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 < al; j++) + { + var vi = avl[j]; + if(vi === i0 || vi === i1 || vi === i2) continue; + + if(PIXI.PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) { + earFound = false; + break; + } + } + } + + if(earFound) + { + tgs.push(i0, i1, i2); + avl.splice((i+1)%al, 1); + al--; + i = 0; + } + else if(i++ > 3*al) + { + // need to flip flip reverse it! + // reset! + if(sign) + { + tgs = []; + avl = []; + for(i = 0; i < n; i++) avl.push(i); + + i = 0; + al = n; + + sign = false; + } + else + { + window.console.log("PIXI Warning: shape too complex to fill"); + return []; + } + } + } + + tgs.push(avl[0], avl[1], avl[2]); + return tgs; +}; /** * Checks if a point is within a triangle @@ -3529,26 +3866,26 @@ PIXI.PolyK.Triangulate = function(p) */ PIXI.PolyK._PointInTriangle = function(px, py, ax, ay, bx, by, cx, cy) { - var v0x = cx-ax; - var v0y = cy-ay; - var v1x = bx-ax; - var v1y = by-ay; - var v2x = px-ax; - var v2y = py-ay; - - var dot00 = v0x*v0x+v0y*v0y; - var dot01 = v0x*v1x+v0y*v1y; - var dot02 = v0x*v2x+v0y*v2y; - var dot11 = v1x*v1x+v1y*v1y; - var dot12 = v1x*v2x+v1y*v2y; - - var invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - var u = (dot11 * dot02 - dot01 * dot12) * invDenom; - var v = (dot00 * dot12 - dot01 * dot02) * invDenom; + var v0x = cx-ax; + var v0y = cy-ay; + var v1x = bx-ax; + var v1y = by-ay; + var v2x = px-ax; + var v2y = py-ay; - // Check if point is in triangle - return (u >= 0) && (v >= 0) && (u + v < 1); -} + var dot00 = v0x*v0x+v0y*v0y; + var dot01 = v0x*v1x+v0y*v1y; + var dot02 = v0x*v2x+v0y*v2y; + var dot11 = v1x*v1x+v1y*v1y; + var dot12 = v1x*v2x+v1y*v2y; + + var invDenom = 1 / (dot00 * dot11 - dot01 * dot01); + var u = (dot11 * dot02 - dot01 * dot12) * invDenom; + var v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Check if point is in triangle + return (u >= 0) && (v >= 0) && (u + v < 1); +}; /** * Checks if a shape is convex @@ -3559,8 +3896,382 @@ PIXI.PolyK._PointInTriangle = function(px, py, ax, ay, bx, by, cx, cy) */ PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) { - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; -} + return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) === sign; +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.initDefaultShaders = function() +{ + + // PIXI.stripShader = new PIXI.StripShader(); +// PIXI.stripShader.init(); + +}; + +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)) { + window.console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +}; + +PIXI.compileProgram = function(gl, 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)) { + window.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(gl) +{ + this.gl = gl; + + /** + * @property {any} program - The WebGL program. + */ + this.program = null; + + /** + * @property {array} fragmentSrc - The fragment shader. + */ + this.fragmentSrc = [ + 'precision lowp float;', + 'varying vec2 vTextureCoord;', + 'varying vec4 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; + + + this.init(); +}; + +/** +* @method PIXI.PixiShader#init +*/ +PIXI.PixiShader.prototype.init = function() +{ + + var gl = this.gl; + + var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc); + + 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(program, 'dimensions'); + + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition'); + this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord'); + this.colorAttribute = gl.getAttribLocation(program, 'aColor'); + + + // Begin worst hack eva // + + // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters? + // maybe its somthing to do with the current state of the gl context. + // Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel + // If theres any webGL people that know why could happen please help :) + if(this.colorAttribute === -1) + { + this.colorAttribute = 2; + } + + // End worst hack eva // + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); + } + + this.initUniforms(); + + this.program = program; +}; + +/** +* Initialises 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#initUniforms +*/ +PIXI.PixiShader.prototype.initUniforms = function() +{ + this.textureCount = 1; + var gl = this.gl; + var uniform; + + for (var key in this.uniforms) + { + uniform = this.uniforms[key]; + + var type = uniform.type; + + if (type === 'sampler2D') + { + uniform._init = false; + + if (uniform.value !== null) + { + this.initSampler2D(uniform); + } + } + else if (type === 'mat2' || type === 'mat3' || type === 'mat4') + { + // These require special handling + uniform.glMatrix = true; + uniform.glValueLength = 1; + + if (type === 'mat2') + { + uniform.glFunc = gl.uniformMatrix2fv; + } + else if (type === 'mat3') + { + uniform.glFunc = gl.uniformMatrix3fv; + } + else if (type === 'mat4') + { + uniform.glFunc = gl.uniformMatrix4fv; + } + } + else + { + // GL function reference + uniform.glFunc = gl['uniform' + type]; + + if (type === '2f' || type === '2i') + { + uniform.glValueLength = 2; + } + else if (type === '3f' || type === '3i') + { + uniform.glValueLength = 3; + } + else if (type === '4f' || type === '4i') + { + uniform.glValueLength = 4; + } + else + { + uniform.glValueLength = 1; + } + } + } + +}; + +/** +* Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture is has loaded) +* +* @method PIXI.PixiShader#initSampler2D +*/ +PIXI.PixiShader.prototype.initSampler2D = function(uniform) +{ + if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded) + { + return; + } + + var gl = this.gl; + + gl.activeTexture(gl['TEXTURE' + this.textureCount]); + gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTexture); + + // Extended texture data + if (uniform.textureData) + { + var data = uniform.textureData; + + // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D); + // GLTextureLinear = mag/min linear, wrap clamp + // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat + // GLTextureNearest = mag/min nearest, wrap clamp + // AudioTexture = whatever + luminance + width 512, height 2, border 0 + // KeyTexture = whatever + luminance + width 256, height 2, border 0 + + // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST + // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT + + var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR; + var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR; + var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE; + var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE; + var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA; + + if (data.repeat) + { + wrapS = gl.REPEAT; + wrapT = gl.REPEAT; + } + + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + + if (data.width) + { + var width = (data.width) ? data.width : 512; + var height = (data.height) ? data.height : 2; + var border = (data.border) ? data.border : 0; + + // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels); + gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null); + } + else + { + // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels); + gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source); + } + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); + } + + gl.uniform1i(uniform.uniformLocation, this.textureCount); + + uniform._init = true; + + this.textureCount++; + +}; + +/** +* Updates the shader uniform values. +* +* @method PIXI.PixiShader#syncUniforms +*/ +PIXI.PixiShader.prototype.syncUniforms = function() +{ + this.textureCount = 1; + var uniform; + var gl = this.gl; + + // This would probably be faster in an array and it would guarantee key order + for (var key in this.uniforms) + { + + uniform = this.uniforms[key]; + + if (uniform.glValueLength === 1) + { + if (uniform.glMatrix === true) + { + uniform.glFunc.call(gl, uniform.uniformLocation, uniform.transpose, uniform.value); + } + else + { + uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value); + } + } + else if (uniform.glValueLength === 2) + { + uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y); + } + else if (uniform.glValueLength === 3) + { + uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z); + } + else if (uniform.glValueLength === 4) + { + uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w); + } + else if (uniform.type === 'sampler2D') + { + if (uniform._init) + { + gl.activeTexture(gl['TEXTURE' + this.textureCount]); + gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture( uniform.value.baseTexture, gl)); + gl.uniform1i(uniform.uniformLocation, this.textureCount); + this.textureCount++; + } + else + { + this.initSampler2D(uniform); + } + } + } + +}; + +PIXI.PixiShader.defaultVertexSrc = [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute vec2 aColor;', + + 'uniform vec2 projectionVector;', + 'uniform vec2 offsetVector;', + + 'varying vec2 vTextureCoord;', + 'varying vec4 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;', + ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = vec4(color * aColor.x, aColor.x);', + '}' +]; + /** @@ -3568,231 +4279,134 @@ PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) */ -/* - * the default suoer fast shader! +PIXI.StripShader = function() +{ + // the webGL program.. + this.program = null; + + 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;', + 'uniform 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 gl = PIXI.gl; + + var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc); + 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.shaderFragmentSrc = [ - "precision mediump float;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "uniform sampler2D uSampler;", - "void main(void) {", - "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", - "gl_FragColor = gl_FragColor * vColor;", - "}" -]; -PIXI.shaderVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - //"uniform mat4 uMVMatrix;", - - "uniform vec2 projectionVector;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", - "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" -]; - -/* - * the triangle strip shader.. - */ - -PIXI.stripShaderFragmentSrc = [ - "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;", - "}" -]; - - -PIXI.stripShaderVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec2 aTextureCoord;", - "attribute float aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "varying vec2 vTextureCoord;", - "varying float vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vTextureCoord = aTextureCoord;", - "vColor = aColor;", - "}" -]; - - -/* - * primitive shader.. - */ - -PIXI.primitiveShaderFragmentSrc = [ - "precision mediump float;", - "varying vec4 vColor;", - "void main(void) {", - "gl_FragColor = vColor;", - "}" -]; - -PIXI.primitiveShaderVertexSrc = [ - "attribute vec2 aVertexPosition;", - "attribute vec4 aColor;", - "uniform mat3 translationMatrix;", - "uniform vec2 projectionVector;", - "uniform float alpha;", - "varying vec4 vColor;", - "void main(void) {", - "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", - "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", - "vColor = aColor * alpha;", - "}" -]; - -PIXI.initPrimitiveShader = function() +PIXI.PrimitiveShader = function(gl) { - var gl = PIXI.gl; + this.gl = gl; - var shaderProgram = PIXI.compileProgram(PIXI.primitiveShaderVertexSrc, PIXI.primitiveShaderFragmentSrc) - - gl.useProgram(shaderProgram); + // the webGL program.. + this.program = null; - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); - - shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); + this.fragmentSrc = [ + 'precision mediump float;', + 'varying vec4 vColor;', - PIXI.primitiveProgram = shaderProgram; -} + 'void main(void) {', + ' gl_FragColor = vColor;', + '}' + ]; -PIXI.initDefaultShader = function() + this.vertexSrc = [ + 'attribute vec2 aVertexPosition;', + 'attribute vec4 aColor;', + 'uniform mat3 translationMatrix;', + 'uniform vec2 projectionVector;', + 'uniform vec2 offsetVector;', + 'uniform float alpha;', + 'uniform vec3 tint;', + '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 * vec4(tint * alpha, alpha);', + '}' + ]; + + this.init(); +}; + +PIXI.PrimitiveShader.prototype.init = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); + var gl = this.gl; - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; -} + var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc); + gl.useProgram(program); -PIXI.initDefaultStripShader = function() -{ - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.stripShaderVertexSrc, PIXI.stripShaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); - shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); - - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.stripShaderProgram = shaderProgram; -} - -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)) { - alert(gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -} + // get and store the uniforms for the shader + this.projectionVector = gl.getUniformLocation(program, 'projectionVector'); + this.offsetVector = gl.getUniformLocation(program, 'offsetVector'); + this.tintColor = gl.getUniformLocation(program, 'tint'); -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); + // get and store the attributes + this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition'); + this.colorAttribute = gl.getAttribLocation(program, 'aColor'); - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - alert("Could not initialise shaders"); - } - - return shaderProgram; -} - - -PIXI.activateDefaultShader = function() -{ - var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; - - gl.useProgram(shaderProgram); - - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); -} - - - -PIXI.activatePrimitiveShader = function() -{ - var gl = PIXI.gl; - - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - - gl.useProgram(PIXI.primitiveProgram); - - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); -} + this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix'); + this.alpha = gl.getUniformLocation(program, 'alpha'); + this.program = program; +}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3805,8 +4419,8 @@ PIXI.activatePrimitiveShader = function() */ PIXI.WebGLGraphics = function() { - -} + +}; /** * Renders the graphics object @@ -3817,66 +4431,69 @@ PIXI.WebGLGraphics = function() * @param graphics {Graphics} * @param projection {Object} */ -PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) +PIXI.WebGLGraphics.renderGraphics = function(graphics, renderSession)//projection, offset) { - 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.primitiveProgram.translationMatrix, false, m); - - gl.uniform2f(PIXI.primitiveProgram.projectionVector, projection.x, projection.y); - - gl.uniform1f(PIXI.primitiveProgram.alpha, graphics.worldAlpha); + var gl = renderSession.gl; + var projection = renderSession.projection, + offset = renderSession.offset, + shader = renderSession.shaderManager.primitiveShader; - gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - - // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); - // its not even used.. but need to be set or it breaks? - // only on pc though.. - - gl.vertexAttribPointer(PIXI.primitiveProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(PIXI.primitiveProgram.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 ); - - // return to default shader... - PIXI.activateDefaultShader(); -} + if(!graphics._webGL[gl.id])graphics._webGL[gl.id] = {points:[], indices:[], lastIndex:0, + buffer:gl.createBuffer(), + indexBuffer:gl.createBuffer()}; + + var webGL = graphics._webGL[gl.id]; + + if(graphics.dirty) + { + graphics.dirty = false; + + if(graphics.clearDirty) + { + graphics.clearDirty = false; + + webGL.lastIndex = 0; + webGL.points = []; + webGL.indices = []; + + } + + PIXI.WebGLGraphics.updateGraphics(graphics, gl); + } + + renderSession.shaderManager.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(shader.translationMatrix, false, m); + + gl.uniform2f(shader.projectionVector, projection.x, -projection.y); + gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); + + gl.uniform3fv(shader.tintColor, PIXI.hex2rgb(graphics.tint)); + + gl.uniform1f(shader.alpha, graphics.worldAlpha); + gl.bindBuffer(gl.ARRAY_BUFFER, webGL.buffer); + + gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); + gl.vertexAttribPointer(shader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); + + // set the index buffer! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGL.indexBuffer); + + gl.drawElements(gl.TRIANGLE_STRIP, webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + + renderSession.shaderManager.deactivatePrimitiveShader(); + + // return to default shader... +// PIXI.activateShader(PIXI.defaultShader); +}; /** * Updates the graphics object @@ -3886,49 +4503,51 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) * @method updateGraphics * @param graphics {Graphics} */ -PIXI.WebGLGraphics.updateGraphics = function(graphics) +PIXI.WebGLGraphics.updateGraphics = function(graphics, gl) { - 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; + var webGL = graphics._webGL[gl.id]; + + for (var i = webGL.lastIndex; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; - 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); -} + if(data.type === PIXI.Graphics.POLY) + { + if(data.fill) + { + if(data.points.length>3) + PIXI.WebGLGraphics.buildPoly(data, webGL); + } + + if(data.lineWidth > 0) + { + PIXI.WebGLGraphics.buildLine(data, webGL); + } + } + else if(data.type === PIXI.Graphics.RECT) + { + PIXI.WebGLGraphics.buildRectangle(data, webGL); + } + else if(data.type === PIXI.Graphics.CIRC || data.type === PIXI.Graphics.ELIP) + { + PIXI.WebGLGraphics.buildCircle(data, webGL); + } + } + + webGL.lastIndex = graphics.graphicsData.length; + + + + webGL.glPoints = new Float32Array(webGL.points); + + gl.bindBuffer(gl.ARRAY_BUFFER, webGL.buffer); + gl.bufferData(gl.ARRAY_BUFFER, webGL.glPoints, gl.STATIC_DRAW); + + webGL.glIndicies = new Uint16Array(webGL.indices); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGL.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, webGL.glIndicies, gl.STATIC_DRAW); +}; /** * Builds a rectangle to draw @@ -3941,59 +4560,63 @@ PIXI.WebGLGraphics.updateGraphics = function(graphics) */ 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); - } - -} + // --- // + // 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 = PIXI.hex2rgb(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) + { + var tempPoints = graphicsData.points; + + graphicsData.points = [x, y, + x + width, y, + x + width, y + height, + x, y + height, + x, y]; + + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; + } +}; /** * Builds a circle to draw @@ -4006,62 +4629,67 @@ PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) */ 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; + // --- // + // 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 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); - } - -} + var totalSegs = 40; + var seg = (Math.PI * 2) / totalSegs ; + + var i = 0; + + if(graphicsData.fill) + { + var color = PIXI.hex2rgb(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 (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) + { + var tempPoints = graphicsData.points; + + graphicsData.points = []; + + for (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); + + graphicsData.points = tempPoints; + } +}; /** * Builds a line to draw @@ -4074,185 +4702,204 @@ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) */ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) { - // TODO OPTIMISE! - - var wrap = true; - var points = graphicsData.points; - if(points.length == 0)return; - - // 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; + // TODO OPTIMISE! + var i = 0; - 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 (denom == 0) { - denom+=1; - } - - 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); -} + 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 (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 = PIXI.hex2rgb(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var px, py, p1x, p1y, p2x, p2y, p3x, p3y; + var perpx, perpy, perp2x, perp2y, perp3x, perp3y; + 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 (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 (i = 0; i < indexCount; i++) + { + indices.push(indexStart++); + } + + indices.push(indexStart-1); +}; /** * Builds a polygon to draw @@ -4265,59 +4912,49 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) */ 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); - }; -} + var points = graphicsData.points; + if(points.length < 6)return; -function HEXtoRGB(hex) { - return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; -} + // 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 = PIXI.hex2rgb(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; + + var i = 0; + + for (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 (i = 0; i < length; i++) + { + verts.push(points[i * 2], points[i * 2 + 1], + r, g, b, alpha); + } +}; /** * @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; +PIXI.glContexts = []; // this is where we store the webGL contexts for easy access. /** * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer @@ -4332,103 +4969,104 @@ PIXI.gl; * @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.. + if(!PIXI.defaultRenderer)PIXI.defaultRenderer = this; - this.transparent = !!transparent; + this.type = PIXI.WEBGL_RENDERER; - this.width = width || 800; - this.height = height || 600; + // do a catch.. only 1 webGL renderer.. + this.transparent = !!transparent; - this.view = view || document.createElement( 'canvas' ); + this.width = width || 800; + this.height = height || 600; + + this.view = view || document.createElement( 'canvas' ); this.view.width = this.width; - this.view.height = this.height; + this.view.height = this.height; - // deal with losing context.. + // 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.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false); + this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false); - this.batchs = []; + this.options = { + alpha: this.transparent, + antialias:!!antialias, // SPEED UP?? + premultipliedAlpha:false, + stencil:true + }; - try - { - PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { - alpha: this.transparent, - antialias:!!antialias, // SPEED UP?? - premultipliedAlpha:false, - stencil:true - }); - } - catch (e) - { - throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); + //try 'experimental-webgl' + try { + this.gl = this.view.getContext('experimental-webgl', this.options); + } catch (e) { + //try 'webgl' + try { + this.gl = this.view.getContext('webgl', this.options); + } catch (e2) { + // fail, not able to get a context + throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); + } } - PIXI.initPrimitiveShader(); - PIXI.initDefaultShader(); - PIXI.initDefaultStripShader(); - - PIXI.activateDefaultShader(); - var gl = this.gl; - PIXI.WebGLRenderer.gl = gl; + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - this.batch = new PIXI.WebGLBatch(gl); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); + PIXI.glContexts[this.glContextId] = gl; - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, this.transparent); + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; - PIXI.projection = new PIXI.Point(400, 300); + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + } + + + + + this.projection = new PIXI.Point(); + this.projection.x = this.width/2; + this.projection.y = -this.height/2; + + this.offset = new PIXI.Point(0, 0); this.resize(this.width, this.height); this.contextLost = false; - this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); -} + // time to create the render managers! each one focuses on managine a state in webGL + this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters + + // + this.renderSession = {}; + this.renderSession.gl = this.gl; + this.renderSession.drawCount = 0; + this.renderSession.shaderManager = this.shaderManager; + this.renderSession.maskManager = this.maskManager; + this.renderSession.filterManager = this.filterManager; + this.renderSession.spriteBatch = this.spriteBatch; + + + gl.useProgram(this.shaderManager.defaultShader.program); + + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, 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 * @@ -4437,73 +5075,94 @@ PIXI.WebGLRenderer.returnBatch = function(batch) */ 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); - } - - // TODO not needed now... - // update children if need be - // best to remove first! - /*for (var i=0; i < stage.__childrenRemoved.length; i++) - { - var group = stage.__childrenRemoved[i].__renderGroup - if(group)group.removeDisplayObject(stage.__childrenRemoved[i]); - }*/ + if(this.contextLost)return; - // 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; - 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 = []; - } -} + // 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; + } + + // update any textures this includes uvs and uploading them to the gpu + PIXI.WebGLRenderer.updateTextures(); + + // update the scene graph + 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); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + gl.clear(gl.COLOR_BUFFER_BIT); + + // this.projection.x = this.width/2; + //this.projection.y = -this.height/2; + + this.renderDisplayObject( stage, this.projection ); + + // interaction + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + /* + //can simulate context loss in Chrome like so: + this.view.onmousedown = function(ev) { + console.dir(this.gl.getSupportedExtensions()); + var ext = ( + gl.getExtension("WEBGL_scompressed_texture_s3tc") + // gl.getExtension("WEBGL_compressed_texture_s3tc") || + // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || + // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") + ); + console.dir(ext); + var loseCtx = this.gl.getExtension("WEBGL_lose_context"); + console.log("killing context"); + loseCtx.loseContext(); + setTimeout(function() { + console.log("restoring context..."); + loseCtx.restoreContext(); + }.bind(this), 1000); + }.bind(this); + */ +}; + +PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection) +{ + // reset the render session data.. + this.renderSession.drawCount = 0; + this.renderSession.currentBlendMode = 9999; + + this.renderSession.projection = projection; + this.renderSession.offset = this.offset; + + // start the sprite batch + this.spriteBatch.begin(this.renderSession); + + // start the filter manager + this.filterManager.begin(this.renderSession, null); + + // render the scene! + displayObject._renderWebGL(this.renderSession); + + // finish the sprite batch + this.spriteBatch.end(); +}; /** * Updates the textures loaded into this webgl renderer @@ -4514,56 +5173,23 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ 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 = []; -} + var i = 0; -/** - * 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(); - } + //TODO break this out into a texture manager... + //for (i = 0; i < PIXI.texturesToUpdate.length; i++) + // PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); - 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); + for (i=0; i < PIXI.Texture.frameUpdates.length; i++) + PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - // reguler... + for (i = 0; i < PIXI.texturesToDestroy.length; i++) + PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - 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); - } -} + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + PIXI.Texture.frameUpdates.length = 0; +}; /** * Destroys a loaded webgl texture @@ -4574,15 +5200,30 @@ PIXI.WebGLRenderer.updateTexture = function(texture) */ PIXI.WebGLRenderer.destroyTexture = function(texture) { - //TODO break this out into a texture manager... - var gl = PIXI.gl; + //TODO break this out into a texture manager... - if(texture._glTexture) - { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); - } -} + for (var i = texture._glTextures.length - 1; i >= 0; i--) + { + var glTexture = texture._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + texture._glTextures.length = 0; +}; + +PIXI.WebGLRenderer.updateTextureFrame = function(texture) +{ + texture.updateFrame = false; + + // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. + // so uv data is stored on the texture itself + texture._updateWebGLuvs(); +}; /** * resizes the webGL view to the specified width and height @@ -4593,24 +5234,80 @@ PIXI.WebGLRenderer.destroyTexture = function(texture) */ PIXI.WebGLRenderer.prototype.resize = function(width, height) { - this.width = width; - this.height = height; + this.width = width; + this.height = height; - this.view.width = width; - this.view.height = height; + this.view.width = width; + this.view.height = height; - this.gl.viewport(0, 0, this.width, this.height); + this.gl.viewport(0, 0, this.width, this.height); - //var projectionMatrix = this.projectionMatrix; + this.projection.x = this.width/2; + this.projection.y = -this.height/2; +}; - PIXI.projection.x = this.width/2; - PIXI.projection.y = this.height/2; +PIXI.createWebGLTexture = function(texture, gl) +{ -// projectionMatrix[0] = 2/this.width; -// projectionMatrix[5] = -2/this.height; -// projectionMatrix[12] = -1; -// projectionMatrix[13] = 1; -} + + if(texture.hasLoaded) + { + texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + 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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); + + // 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); + } + + return texture._glTextures[gl.id]; +}; + +PIXI.updateWebGLTexture = function(texture, gl) +{ + if( texture._glTextures[gl.id] ) + { + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + 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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); + + // 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); + } + +}; /** * Handles a lost webgl context @@ -4621,9 +5318,9 @@ PIXI.WebGLRenderer.prototype.resize = function(width, height) */ PIXI.WebGLRenderer.prototype.handleContextLost = function(event) { - event.preventDefault(); - this.contextLost = true; -} + event.preventDefault(); + this.contextLost = true; +}; /** * Handles a restored webgl context @@ -4632,1638 +5329,1230 @@ PIXI.WebGLRenderer.prototype.handleContextLost = function(event) * @param event {Event} * @private */ -PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) +PIXI.WebGLRenderer.prototype.handleContextRestored = function() { - 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; - - 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]; - - this.verticies[index + 0 ] = a * w1 + c * h1 + tx; - this.verticies[index + 1 ] = d * h1 + b * w1 + ty; - - this.verticies[index + 2 ] = a * w0 + c * h1 + tx; - this.verticies[index + 3 ] = d * h1 + b * w0 + ty; - - this.verticies[index + 4 ] = a * w0 + c * h0 + tx; - this.verticies[index + 5 ] = d * h0 + b * w0 + ty; - - this.verticies[index + 6] = a * w1 + c * h0 + tx; - this.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; - - 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; - } - - // TODO this probably could do with some optimisation.... - if(displayObject.cacheAlpha != displayObject.worldAlpha) - { - displayObject.cacheAlpha = displayObject.worldAlpha; - - var colorIndex = indexRun * 4; - this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; - this.dirtyColors = true; - } - } - else - { - index = indexRun * 8; - - this.verticies[index + 0 ] = 0; - this.verticies[index + 1 ] = 0; - - this.verticies[index + 2 ] = 0; - this.verticies[index + 3 ] = 0; - - this.verticies[index + 4 ] = 0; - this.verticies[index + 5 ] = 0; - - this.verticies[index + 6] = 0; - this.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.shaderProgram; - 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.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - if(this.dirtyUVS) - { - this.dirtyUVS = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); + //try 'experimental-webgl' + try { + this.gl = this.view.getContext('experimental-webgl', this.options); + } catch (e) { + //try 'webgl' + try { + this.gl = this.view.getContext('webgl', this.options); + } catch (e2) { + // fail, not able to get a context + throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); + } } - gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + var gl = this.gl; + gl.id = PIXI.WebGLRenderer.glContextId ++; - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); - // update color! - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - if(this.dirtyColors) + // need to set the context... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + + + this.renderSession.gl = this.gl; + + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, this.transparent); + + this.gl.viewport(0, 0, this.width, this.height); + + for(var key in PIXI.TextureCache) { - this.dirtyColors = false; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); - } + var texture = PIXI.TextureCache[key].baseTexture; + texture._glTextures = []; + } - gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + this.contextLost = false; - // dont need to upload! +}; + +PIXI.WebGLRenderer.glContextId = 0; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.WebGLMaskManager = function(gl) +{ + this.maskStack = []; + this.maskPosition = 0; + + this.setContext(gl); +}; + +PIXI.WebGLMaskManager.prototype.setContext = function(gl) +{ + this.gl = gl; +}; + +PIXI.WebGLMaskManager.prototype.pushMask = function(maskData, renderSession) +{ + var gl = this.gl; + + if(this.maskStack.length === 0) + { + gl.enable(gl.STENCIL_TEST); + gl.stencilFunc(gl.ALWAYS,1,1); + } + + // maskData.visible = false; + + this.maskStack.push(maskData); + + gl.colorMask(false, false, false, true); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); + + PIXI.WebGLGraphics.renderGraphics(maskData, renderSession); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0, this.maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); +}; + +PIXI.WebGLMaskManager.prototype.popMask = function(renderSession) +{ + var gl = this.gl; + + var maskData = this.maskStack.pop(); + + 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, renderSession); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,this.maskStack.length); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + } + + if(this.maskStack.length === 0)gl.disable(gl.STENCIL_TEST); +}; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.WebGLShaderManager = function(gl) +{ + this.setContext(gl); + + // the final one is used for the rendering strips + //this.stripShader = new PIXI.StripShader(gl); +}; + +PIXI.WebGLShaderManager.prototype.setContext = function(gl) +{ + this.gl = gl; + + // the next one is used for rendering primatives + this.primitiveShader = new PIXI.PrimitiveShader(gl); + + // this shader is used for the default sprite rendering + this.defaultShader = new PIXI.PixiShader(gl); + + var shaderProgram = this.defaultShader.program; + + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(this.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(this.defaultShader.colorAttribute); + gl.enableVertexAttribArray(this.defaultShader.aTextureCoord); + + +}; + +PIXI.WebGLShaderManager.prototype.activatePrimitiveShader = function() +{ + var gl = this.gl; + + gl.useProgram(this.primitiveShader.program); + + gl.disableVertexAttribArray(this.defaultShader.aVertexPosition); + gl.disableVertexAttribArray(this.defaultShader.colorAttribute); + gl.disableVertexAttribArray(this.defaultShader.aTextureCoord); + + gl.enableVertexAttribArray(this.primitiveShader.aVertexPosition); + gl.enableVertexAttribArray(this.primitiveShader.colorAttribute); +}; + +PIXI.WebGLShaderManager.prototype.deactivatePrimitiveShader = function() +{ + var gl = this.gl; + + gl.useProgram(this.defaultShader.program); + + gl.disableVertexAttribArray(this.primitiveShader.aVertexPosition); + gl.disableVertexAttribArray(this.primitiveShader.colorAttribute); + + gl.enableVertexAttribArray(this.defaultShader.aVertexPosition); + gl.enableVertexAttribArray(this.defaultShader.colorAttribute); + gl.enableVertexAttribArray(this.defaultShader.aTextureCoord); +}; +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ + * for creating the original pixi version! + * + * Heavily inspired by LibGDX's WebGLSpriteBatch: + * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java + */ + +PIXI.WebGLSpriteBatch = function(gl) +{ + + + this.size = 2000; + this.vertSize = 6; + + //the total number of floats in our batch + var numVerts = this.size * 4 * this.vertSize; + //the total number of indices in our batch + var numIndices = this.size * 6; + + //vertex data + this.vertices = new Float32Array(numVerts); + //index data + this.indices = new Uint16Array(numIndices); + + this.lastIndexCount = 0; + + for (var i=0, j=0; i < numIndices; i += 6, j += 4) + { + this.indices[i + 0] = j + 0; + this.indices[i + 1] = j + 1; + this.indices[i + 2] = j + 2; + this.indices[i + 3] = j + 0; + this.indices[i + 4] = j + 2; + this.indices[i + 5] = j + 3; + } + + + this.drawing = false; + this.currentBatchSize = 0; + this.currentBaseTexture = null; + + this.setContext(gl); +}; + +PIXI.WebGLSpriteBatch.prototype.setContext = function(gl) +{ + this.gl = gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + // 65535 is max index, so 65535 / 6 = 10922. + + + //upload the index data + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); + + this.currentBlendMode = 99999; +}; + +PIXI.WebGLSpriteBatch.prototype.begin = function(renderSession) +{ + this.renderSession = renderSession; + this.shader = this.renderSession.shaderManager.defaultShader; + + this.start(); +}; + +PIXI.WebGLSpriteBatch.prototype.end = function() +{ + this.flush(); +}; + + +PIXI.WebGLSpriteBatch.prototype.render = function(sprite) +{ + // check texture.. + if(sprite.texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size) + { + this.flush(); + this.currentBaseTexture = sprite.texture.baseTexture; + } + + + // check blend mode + if(sprite.blendMode !== this.currentBlendMode) + { + this.setBlendMode(sprite.blendMode); + } + + // get the uvs for the texture + var uvs = sprite._uvs || sprite.texture._uvs; + // if the uvs have not updated then no point rendering just yet! + if(!uvs)return; + + // get the sprites current alpha + var alpha = sprite.worldAlpha; + var tint = sprite.tint; + + var verticies = this.vertices; + + var width = sprite.texture.frame.width; + var height = sprite.texture.frame.height; + + // TODO trim?? + var aX = sprite.anchor.x; + var aY = sprite.anchor.y; + + var w0, w1, h0, h1; + + if (sprite.texture.trimmed) + { + // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords.. + var trim = sprite.texture.trim; + + w1 = trim.x - aX * trim.realWidth; + w0 = w1 + width; + + h1 = trim.y - aY * trim.realHeight; + h0 = h1 + height; + } + else + { + w0 = (width ) * (1-aX); + w1 = (width ) * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + } + + var index = this.currentBatchSize * 4 * this.vertSize; + + var worldTransform = sprite.worldTransform; + + var a = worldTransform[0]; + var b = worldTransform[3]; + var c = worldTransform[1]; + var d = worldTransform[4]; + var tx = worldTransform[2]; + var ty = worldTransform[5]; + + // xy + verticies[index++] = a * w1 + c * h1 + tx; + verticies[index++] = d * h1 + b * w1 + ty; + // uv + verticies[index++] = uvs[0]; + verticies[index++] = uvs[1]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w0 + c * h1 + tx; + verticies[index++] = d * h1 + b * w0 + ty; + // uv + verticies[index++] = uvs[2]; + verticies[index++] = uvs[3]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w0 + c * h0 + tx; + verticies[index++] = d * h0 + b * w0 + ty; + // uv + verticies[index++] = uvs[4]; + verticies[index++] = uvs[5]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w1 + c * h0 + tx; + verticies[index++] = d * h0 + b * w1 + ty; + // uv + verticies[index++] = uvs[6]; + verticies[index++] = uvs[7]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // increment the batchs + this.currentBatchSize++; + + +}; + +PIXI.WebGLSpriteBatch.prototype.renderTilingSprite = function(tilingSprite) +{ + var texture = tilingSprite.tilingTexture; + + if(texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size) + { + this.flush(); + this.currentBaseTexture = texture.baseTexture; + } + + // check blend mode + if(tilingSprite.blendMode !== this.currentBlendMode) + { + this.setBlendMode(tilingSprite.blendMode); + } + + // set the textures uvs temporarily + // TODO create a seperate texture so that we can tile part of a texture + + if(!tilingSprite._uvs)tilingSprite._uvs = new Float32Array(8); + + var uvs = tilingSprite._uvs; + + var offsetX = tilingSprite.tilePosition.x/texture.baseTexture.width; + var offsetY = tilingSprite.tilePosition.y/texture.baseTexture.height; + + var scaleX = (tilingSprite.width / texture.baseTexture.width) / (tilingSprite.tileScale.x * tilingSprite.tileScaleOffset.x); + var scaleY = (tilingSprite.height / texture.baseTexture.height) / (tilingSprite.tileScale.y * tilingSprite.tileScaleOffset.y); + + uvs[0] = 0 - offsetX; + uvs[1] = 0 - offsetY; + + uvs[2] = (1 * scaleX) - offsetX; + uvs[3] = 0 - offsetY; + + uvs[4] = (1 * scaleX) - offsetX; + uvs[5] = (1 * scaleY) - offsetY; + + uvs[6] = 0 - offsetX; + uvs[7] = (1 *scaleY) - offsetY; + + + // get the tilingSprites current alpha + var alpha = tilingSprite.worldAlpha; + var tint = tilingSprite.tint; + + var verticies = this.vertices; + + var width = tilingSprite.width; + var height = tilingSprite.height; + + // TODO trim?? + var aX = tilingSprite.anchor.x; // - tilingSprite.texture.trim.x + var aY = tilingSprite.anchor.y; //- tilingSprite.texture.trim.y + var w0 = width * (1-aX); + var w1 = width * -aX; + + var h0 = height * (1-aY); + var h1 = height * -aY; + + var index = this.currentBatchSize * 4 * this.vertSize; + + var worldTransform = tilingSprite.worldTransform; + + var a = worldTransform[0]; + var b = worldTransform[3]; + var c = worldTransform[1]; + var d = worldTransform[4]; + var tx = worldTransform[2]; + var ty = worldTransform[5]; + + // xy + verticies[index++] = a * w1 + c * h1 + tx; + verticies[index++] = d * h1 + b * w1 + ty; + // uv + verticies[index++] = uvs[0]; + verticies[index++] = uvs[1]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w0 + c * h1 + tx; + verticies[index++] = d * h1 + b * w0 + ty; + // uv + verticies[index++] = uvs[2]; + verticies[index++] = uvs[3]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w0 + c * h0 + tx; + verticies[index++] = d * h0 + b * w0 + ty; + // uv + verticies[index++] = uvs[4]; + verticies[index++] = uvs[5]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // xy + verticies[index++] = a * w1 + c * h0 + tx; + verticies[index++] = d * h0 + b * w1 + ty; + // uv + verticies[index++] = uvs[6]; + verticies[index++] = uvs[7]; + // color + verticies[index++] = alpha; + verticies[index++] = tint; + + // increment the batchs + this.currentBatchSize++; +}; + +PIXI.WebGLSpriteBatch.prototype.flush = function() +{ + // If the batch is length 0 then return as there is nothing to draw + if (this.currentBatchSize===0)return; + + var gl = this.gl; + + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.currentBaseTexture, gl)); + + // upload the verts to the buffer + var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); + + // now draw those suckas! + gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0); + + // then reset the batch! + this.currentBatchSize = 0; + + // increment the draw count + this.renderSession.drawCount++; +}; + + +PIXI.WebGLSpriteBatch.prototype.stop = function() +{ + this.flush(); +}; + +PIXI.WebGLSpriteBatch.prototype.start = function() +{ + var gl = this.gl; + + // bind the main texture + gl.activeTexture(gl.TEXTURE0); + + // bind the buffers + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - var len = end - start; + // set the projection + var projection = this.renderSession.projection; + gl.uniform2f(this.shader.projectionVector, projection.x, projection.y); + + // set the pointers + var stride = this.vertSize * 4; + gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); + + // set the blend mode.. + if(this.currentBlendMode !== PIXI.blendModes.NORMAL) + { + this.setBlendMode(PIXI.blendModes.NORMAL); + } +}; + +PIXI.WebGLSpriteBatch.prototype.setBlendMode = function(blendMode) +{ + this.flush(); + + this.currentBlendMode = blendMode; + + var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode]; + this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); +}; + - // 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) + +PIXI.WebGLFilterManager = function(gl, transparent) { - this.gl = gl; - this.root; - - this.backgroundColor; - this.batchs = []; - this.toRemove = []; -} + this.transparent = 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) -{ - PIXI.WebGLRenderer.updateTextures(); - - var gl = this.gl; - - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - 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; - } - - // non sprite batch.. - 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.Graphics) - { - if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); - } - else if(renderable instanceof PIXI.FilterBlock) - { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } - } - } - -} - -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - -/** - * Renders a specific displayObject - * - * @method renderSpecific - * @param displayObject {DisplayObject} - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection) -{ - PIXI.WebGLRenderer.updateTextures(); - - var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - - // 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) - { - nextRenderable = nextRenderable._iNext; - if(nextRenderable.renderable && nextRenderable.__renderGroup)break; - } - var startBatch = nextRenderable.batch; - - 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; - var endBatch; - var lastItem = displayObject; - while(lastItem.children.length > 0) - { - lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; - } - - 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; - } - - // 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) - { - /* - * for now only masks are supported.. - */ - - var gl = PIXI.gl; - - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - 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) - { - 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) - { - 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); + this.filterStack = []; -// return ( (x > 0) && ((x & (x - 1)) == 0) ); + this.offsetX = 0; + this.offsetY = 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; - } -} + this.setContext(gl); +}; -/** - * Renders a Strip - * - * @method renderStrip - * @param strip {Strip} The strip to render - * @param projection {Object} - * @private - */ -PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) +// API + +PIXI.WebGLFilterManager.prototype.setContext = function(gl) { - var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) + this.gl = gl; + this.texturePool = []; - - gl.useProgram(PIXI.stripShaderProgram); + this.initShaderBuffers(); +}; - var m = PIXI.mat3.clone(strip.worldTransform); - - PIXI.mat3.transpose(m); - - // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); +PIXI.WebGLFilterManager.prototype.begin = function(renderSession, buffer) +{ + this.renderSession = renderSession; + this.defaultShader = renderSession.shaderManager.defaultShader; -/* - 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); - } - */ - - - if(!strip.dirty) - { - - gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) - gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 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(shaderProgram.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(shaderProgram.vertexPositionAttribute, 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(shaderProgram.textureCoordAttribute, 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.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) - gl.vertexAttribPointer(shaderProgram.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); - - } - //console.log(gl.TRIANGLE_STRIP); - - gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); + var projection = this.renderSession.projection; + + this.width = projection.x * 2; + this.height = -projection.y * 2; + this.buffer = buffer; +}; + +PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock) +{ + var gl = this.gl; + + var projection = this.renderSession.projection; + var offset = this.renderSession.offset; + + + // 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.gl, this.width, this.height); + } + else + { + texture.resize(this.width, this.height); + } + + gl.bindTexture(gl.TEXTURE_2D, texture.texture); + +// this.getBounds(filterBlock.target); + + filterBlock.target.filterArea = filterBlock.target.getBounds(); + // console.log(filterBlock.target.filterArea) + // console.log(filterBlock.target.filterArea); + // 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); + + projection.x = filterArea.width/2; + projection.y = -filterArea.height/2; + + offset.x = -filterArea.x; + offset.y = -filterArea.y; + + //console.log(PIXI.defaultShader.projectionVector) + // update projection + gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); + gl.uniform2f(this.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 = this.gl; + var filterBlock = this.filterStack.pop(); + var filterArea = filterBlock.target.filterArea; + var texture = filterBlock._glFilterTexture; + var projection = this.renderSession.projection; + var offset = this.renderSession.offset; + + 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.gl, 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]; + 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.. + projection.x = sizeX/2; + projection.y = -sizeY/2; + + offset.x = offsetX; + offset.y = offsetY; + + 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 the blend mode! + //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) + + // 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(this.defaultShader.program); + gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2); + gl.uniform2f(this.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 = this.gl; + var shader = filter.shaders[gl.id]; + + if(!shader) + { + shader = new PIXI.PixiShader(gl); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shaders[gl.id] = 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.ARRAY_BUFFER, this.colorBuffer); + gl.vertexAttribPointer(shader.colorAttribute, 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 ); + + this.renderSession.drawCount++; +}; + +PIXI.WebGLFilterManager.prototype.initShaderBuffers = function() +{ + var gl = this.gl; + + // create some buffers + this.vertexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = 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); + + this.colorArray = new Float32Array([1.0, 0xFFFFFF, + 1.0, 0xFFFFFF, + 1.0, 0xFFFFFF, + 1.0, 0xFFFFFF]); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + this.colorArray, + 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.FilterTexture = function(gl, width, height) +{ + this.gl = 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.clear = function() +{ + var gl = this.gl; - gl.useProgram(PIXI.shaderProgram); -} + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); +}; + +PIXI.FilterTexture.prototype.resize = function(width, height) +{ + if(this.width === width && this.height === height) return; + + this.width = width; + this.height = height; + + var gl = this.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); + +}; /** - * Renders a TilingSprite - * - * @method renderTilingSprite - * @param sprite {TilingSprite} The tiling sprite to render - * @param projectionMatrix {Object} - * @private + * @author Mat Groves + * + * */ -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); -} +PIXI.CanvasMaskManager = function() +{ + +}; + +PIXI.CanvasMaskManager.prototype.pushMask = function(maskData, context) +{ + context.save(); + + //maskData.visible = false; + // maskData.alpha = 0; + + var cacheAlpha = maskData.alpha; + var transform = maskData.worldTransform; + + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + + PIXI.CanvasGraphics.renderGraphicsMask(maskData, context); + + context.clip(); + + maskData.worldAlpha = cacheAlpha; +}; + +PIXI.CanvasMaskManager.prototype.popMask = function(context) +{ + context.restore(); +}; /** - * Initializes a strip to be rendered - * - * @method initStrip - * @param strip {Strip} The strip to initialize - * @private + * @author Mat Groves + * + * */ -PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) + +PIXI.CanvasTinter = function() { - // 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); + /// this.textureCach +}; - gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); +//PIXI.CanvasTinter.cachTint = true; + + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color) +{ + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.CanvasTinter.roundColor(color); + + var stringColor = "#" + ("00000" + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if(texture.tintCache[stringColor]) return texture.tintCache[stringColor]; + + // clone texture.. + var canvas = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + + //PIXI.CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + + + PIXI.CanvasTinter.tintMethod(texture, color, canvas); + + if(PIXI.CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +}; + +PIXI.CanvasTinter.tintWithMultiply = function(texture, color, canvas) +{ + var context = canvas.getContext( "2d" ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = "#" + ("00000" + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = "multiply"; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = "destination-atop"; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); +}; + +PIXI.CanvasTinter.tintWithOverlay = function(texture, color, canvas) +{ + var context = canvas.getContext( "2d" ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + + + context.globalCompositeOperation = "copy"; + context.fillStyle = "#" + ("00000" + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = "destination-atop"; + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + //context.globalCompositeOperation = "copy"; + +}; + + +PIXI.CanvasTinter.tintWithPerPixel = function(texture, color, canvas) +{ + var context = canvas.getContext( "2d" ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.globalCompositeOperation = "copy"; + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + var rgbValues = PIXI.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, frame.width, frame.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.min(255, Math.round(rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, Math.round(rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, Math.round(rgbValues[2] / step) * step); + + return PIXI.rgb2hex(rgbValues); +}; + +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.canUseMultiply = PIXI.canUseNewCanvasBlendModes(); + +PIXI.CanvasTinter.tintMethod = PIXI.CanvasTinter.canUseMultiply ? PIXI.CanvasTinter.tintWithMultiply : PIXI.CanvasTinter.tintWithPerPixel; - 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 */ - /** * 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 :) @@ -6277,49 +6566,95 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) */ PIXI.CanvasRenderer = function(width, height, view, transparent) { - this.transparent = transparent; + PIXI.defaultRenderer = PIXI.defaultRenderer || this; - /** - * The width of the canvas view - * - * @property width - * @type Number - * @default 800 - */ - this.width = width || 800; + this.type = PIXI.CANVAS_RENDERER; - /** - * The height of the canvas view - * - * @property height - * @type Number - * @default 600 - */ - this.height = height || 600; + this.transparent = transparent; - /** - * The canvas element that the everything is drawn to - * - * @property view - * @type Canvas - */ - this.view = view || document.createElement( 'canvas' ); + if(!PIXI.blendModesCanvas) + { + PIXI.blendModesCanvas = []; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } + } - /** - * The canvas context that the everything is drawn to - * @property context - * @type Canvas 2d Context - */ - this.context = this.view.getContext("2d"); + /** + * 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" ); + + //some filter variables + this.smoothProperty = null; + + if("imageSmoothingEnabled" in this.context) + this.smoothProperty = "imageSmoothingEnabled"; + else if("webkitImageSmoothingEnabled" in this.context) + this.smoothProperty = "webkitImageSmoothingEnabled"; + else if("mozImageSmoothingEnabled" in this.context) + this.smoothProperty = "mozImageSmoothingEnabled"; + else if("oImageSmoothingEnabled" in this.context) + this.smoothProperty = "oImageSmoothingEnabled"; + + this.scaleMode = null; + + this.refresh = true; + // hack to enable some hardware acceleration! + //this.view.style["transform"] = "translatez(0)"; - 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; -} + this.view.height = this.height; + this.count = 0; + + this.maskManager = new PIXI.CanvasMaskManager(); + + this.renderSession = {}; + this.renderSession.context = this.context; + this.renderSession.maskManager = this.maskManager; + +}; // constructor PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; @@ -6332,44 +6667,41 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ 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; + //stage.__childrenAdded = []; + //stage.__childrenRemoved = []; - this.context.setTransform(1,0,0,1,0,0); - this.context.clearRect(0, 0, this.width, this.height) + // update textures if need be + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + + 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 = []; - } - - -} + 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.length = 0; + } +}; /** * resizes the canvas view to the specified width and height @@ -6380,12 +6712,12 @@ PIXI.CanvasRenderer.prototype.render = function(stage) */ PIXI.CanvasRenderer.prototype.resize = function(width, height) { - this.width = width; - this.height = height; - - this.view.width = width; - this.view.height = height; -} + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; +}; /** * Renders a display object @@ -6394,109 +6726,15 @@ PIXI.CanvasRenderer.prototype.resize = function(width, height) * @param displayObject {DisplayObject} The displayObject to render * @private */ -PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject, context) { - // 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) - { - 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) - { - 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.open) - { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - } - else - { - context.restore(); - } - } - // count++ - displayObject = displayObject._iNext; - - - } - while(displayObject != testObject) + // no loger recurrsive! + //var transform; + //var context = this.context; - -} + this.renderSession.context = context || this.context; + displayObject._renderCanvas(this.renderSession); +}; /** * Renders a flat strip @@ -6507,66 +6745,30 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) */ 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(); -} + var context = this.context; + var verticies = strip.verticies; -/** - * 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); - + 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 strip @@ -6577,58 +6779,77 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) */ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { - var context = this.context; + 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; + // 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(); - 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(); - }; - -} + var deltaA = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; + var deltaB = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; + var deltaC = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; + var deltaD = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; + var deltaE = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; + var deltaF = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; + + context.transform(deltaA / delta, deltaD / delta, + deltaB / delta, deltaE / delta, + deltaC / delta, deltaF / delta); + + context.drawImage(strip.texture.baseTexture.source, 0, 0); + context.restore(); + } +}; + +PIXI.CanvasBuffer = function(width, height) +{ + this.width = width; + this.height = height; + + this.canvas = document.createElement( "canvas" ); + this.context = this.canvas.getContext( "2d" ); + +// this.context.f + this.canvas.width = width; + this.canvas.height = height; +}; + +PIXI.CanvasBuffer.prototype.clear = function() +{ + this.context.clearRect(0,0, this.width, this.height); +}; + +PIXI.CanvasBuffer.prototype.resize = function(width, height) +{ + this.width = this.canvas.width = width; + this.height = this.canvas.height = height; +}; + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -6642,8 +6863,8 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - -} + +}; /* @@ -6657,129 +6878,128 @@ PIXI.CanvasGraphics = function() */ 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); + var worldAlpha = graphics.worldAlpha; + var color = ''; - 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) - { - - // TODO - need to be Undefined! - if(data.fillColor != undefined) - { - 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(); - } - } - - }; -} + 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) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var ellipseData = data.points; + + var w = ellipseData[2] * 2; + var h = ellipseData[3] * 2; + + var x = ellipseData[0] - w/2; + var y = ellipseData[1] - h/2; + + context.beginPath(); + + var kappa = 0.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 @@ -6792,83 +7012,82 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) */ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { - var worldAlpha = graphics.worldAlpha; - - var len = graphics.graphicsData.length; - 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(); - } - - - }; -} + var len = graphics.graphicsData.length; + + if(len === 0) return; + + if(len > 1) + { + len = 1; + window.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) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + var ellipseData = data.points; + + var w = ellipseData[2] * 2; + var h = ellipseData[3] * 2; + + var x = ellipseData[0] - w/2; + var y = ellipseData[1] - h/2; + + context.beginPath(); + + var kappa = 0.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 @@ -6876,19 +7095,19 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * 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 + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { - PIXI.DisplayObjectContainer.call( this ); - - this.renderable = true; + PIXI.DisplayObjectContainer.call( this ); + + this.renderable = true; /** * The alpha of the fill of this graphics object @@ -6896,7 +7115,7 @@ PIXI.Graphics = function() * @property fillAlpha * @type Number */ - this.fillAlpha = 1; + this.fillAlpha = 1; /** * The width of any lines drawn @@ -6904,7 +7123,7 @@ PIXI.Graphics = function() * @property lineWidth * @type Number */ - this.lineWidth = 0; + this.lineWidth = 0; /** * The color of any lines drawn @@ -6912,7 +7131,7 @@ PIXI.Graphics = function() * @property lineColor * @type String */ - this.lineColor = "black"; + this.lineColor = "black"; /** * Graphics data @@ -6921,8 +7140,12 @@ PIXI.Graphics = function() * @type Array * @private */ - this.graphicsData = []; + this.graphicsData = []; + this.tint = 0xFFFFFF;// * Math.random(); + + this.blendMode = PIXI.blendModes.NORMAL; + /** * Current path * @@ -6930,13 +7153,53 @@ PIXI.Graphics = function() * @type Object * @private */ - this.currentPath = {points:[]}; -} + this.currentPath = {points:[]}; + + this._webGL = []; + + this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; +}; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ +Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { + get: function() { + return this._cacheAsBitmap; + }, + set: function(value) { + this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + + } +}); + + /** * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. * @@ -6947,17 +7210,17 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; */ 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); -} + if (!this.currentPath.points.length) this.graphicsData.pop(); + + this.lineWidth = lineWidth || 0; + this.lineColor = color || 0; + this.lineAlpha = (arguments.length < 3) ? 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). @@ -6968,15 +7231,15 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) */ 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); -} + if (!this.currentPath.points.length) 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); @@ -6988,9 +7251,9 @@ PIXI.Graphics.prototype.moveTo = function(x, y) */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); - this.dirty = true; -} + this.currentPath.points.push(x, y); + this.dirty = true; +}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -7002,10 +7265,11 @@ PIXI.Graphics.prototype.lineTo = function(x, y) */ PIXI.Graphics.prototype.beginFill = function(color, alpha) { - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha == undefined) ? 1 : alpha; -} + + this.filling = true; + this.fillColor = color || 0; + this.fillAlpha = (arguments.length < 2) ? 1 : alpha; +}; /** * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. @@ -7014,10 +7278,10 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) */ PIXI.Graphics.prototype.endFill = function() { - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; -} + this.filling = false; + this.fillColor = null; + this.fillAlpha = 1; +}; /** * @method drawRect @@ -7029,15 +7293,15 @@ PIXI.Graphics.prototype.endFill = function() */ 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; -} + if (!this.currentPath.points.length) 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. @@ -7049,36 +7313,38 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) */ 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; -} + + if (!this.currentPath.points.length) 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. + * Draws an ellipse. * - * @method drawElipse + * @method drawEllipse * @param x {Number} * @param y {Number} * @param width {Number} * @param height {Number} */ -PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) +PIXI.Graphics.prototype.drawEllipse = 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; -} + + if (!this.currentPath.points.length) 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. @@ -7087,13 +7353,293 @@ PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) */ PIXI.Graphics.prototype.clear = function() { - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; -} + this.lineWidth = 0; + this.filling = false; + + this.dirty = true; + this.clearDirty = true; + this.graphicsData = []; + + this.bounds = null; //new PIXI.Rectangle(); +}; + +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; + +PIXI.Graphics.prototype._renderWebGL = function(renderSession) +{ + // if the sprite is not visible or the alpha is 0 then no need to render this element + if(this.visible === false || this.alpha === 0 || this.isMask === true)return; + + if(this._cacheAsBitmap) + { + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } + + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + // only rende rif it has children! + if(this.children.length) + { + renderSession.spriteBatch.start(); + + // simple render children! + for(var i=0, j=this.children.length; i 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; + + var bounds = this._bounds; + + bounds.x = minX; + bounds.width = maxX - minX; + + bounds.y = minY; + bounds.height = maxY - minY; + + return bounds; +}; + +PIXI.Graphics.prototype.updateBounds = function() +{ + + 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; + } + } + } + + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); +}; + +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -7107,66 +7653,66 @@ PIXI.Graphics.ELIP = 3; 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; -} + 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 ); @@ -7174,51 +7720,48 @@ 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; -} + //TODO SET THE TEXTURES + //TODO VISIBILITY -PIXI.Strip.prototype.onTextureUpdate = function(event) + // stop current texture + this.texture = texture; + this.width = texture.frame.width; + this.height = texture.frame.height; + this.updateFrame = true; +}; + +PIXI.Strip.prototype.onTextureUpdate = function() { - this.updateFrame = true; -} + 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(); -} + 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 = new Array(points.length * 4); + this.uvs = new Array(points.length * 4); + this.colors = new Array(points.length * 2); + this.indices = new Array(points.length * 2); + } + + this.refresh(); +}; // constructor @@ -7227,145 +7770,138 @@ 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; - } -} + var points = this.points; + if(points.length < 1) return; + + var uvs = this.uvs; + + var lastPoint = points[0]; + var indices = this.indices; + var colors = this.colors; + + 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, + point, index, amount; + + for (var i = 1; i < total; i++) + { + + point = points[i]; + index = i * 4; + // time to do some smart drawing! + 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 ); -} + var points = this.points; + if(points.length < 1)return; + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + + this.count-=0.2; + + var verticies = this.verticies; + verticies[0] = lastPoint.x + perp.x; + verticies[1] = lastPoint.y + perp.y; //+ 200 + verticies[2] = lastPoint.x - perp.x; + verticies[3] = lastPoint.y - perp.y;//+200 + // time to do some smart drawing! + + var total = points.length, + point, index, ratio, perpLength, num; + + for (var i = 1; i < total; i++) + { + point = points[i]; + 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; + + ratio = (1 - (i / (total-1))) * 10; + + if(ratio > 1) ratio = 1; + + perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); + 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; -} - - - - + // stop current texture + this.texture = texture; + this.updateFrame = true; +}; /** * @author Mat Groves http://matgroves.com/ @@ -7383,86 +7919,321 @@ PIXI.Rope.prototype.setTexture = function(texture) */ PIXI.TilingSprite = function(texture, width, height) { - PIXI.DisplayObjectContainer.call( this ); + PIXI.Sprite.call( this, texture); - /** - * The texture that the sprite is using - * - * @property texture - * @type Texture - */ - this.texture = texture; + this.width = width || 100; + this.height = height || 100; - /** - * The width of the tiling sprite - * - * @property width - * @type Number - */ - this.width = width; + /** + * The scaling of the image that is being tiled + * + * @property tileScale + * @type Point + */ + this.tileScale = new PIXI.Point(1,1); - /** - * 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); + this.tileScaleOffset = 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); - /** - * 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.renderable = true; - - this.blendMode = PIXI.blendModes.NORMAL -} + this.tint = 0xFFFFFF; + this.blendMode = PIXI.blendModes.NORMAL; +}; // constructor -PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.TilingSprite.prototype = Object.create( PIXI.Sprite.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 + * The width of the sprite, setting this will actually modify the scale to acheive the value set * - * @method onTextureUpdate - * @param event - * @private + * @property width + * @type Number */ -PIXI.TilingSprite.prototype.onTextureUpdate = function(event) +Object.defineProperty(PIXI.TilingSprite.prototype, 'width', { + get: function() { + return this._width; + }, + set: function(value) { + + this._width = value; + } +}); + +/** + * The height of the TilingSprite, setting this will actually modify the scale to acheive the value set + * + * @property height + * @type Number + */ +Object.defineProperty(PIXI.TilingSprite.prototype, 'height', { + get: function() { + return this._height; + }, + set: function(value) { + this._height = value; + } +}); + +PIXI.TilingSprite.prototype.onTextureUpdate = function() { - this.updateFrame = true; -} + // so if _width is 0 then width was not set.. + //console.log("HI MUM") + + + this.updateFrame = true; +}; + +PIXI.TilingSprite.prototype._renderWebGL = function(renderSession) +{ + + if(this.visible === false || this.alpha === 0)return; + + var i,j; + + if(this.mask || this.filters) + { + if(this.mask) + { + renderSession.spriteBatch.stop(); + renderSession.maskManager.pushMask(this.mask, renderSession.projection); + renderSession.spriteBatch.start(); + } + + if(this.filters) + { + renderSession.spriteBatch.flush(); + renderSession.filterManager.pushFilter(this._filterBlock); + } + + if(!this.tilingTexture)this.generateTilingTexture(true); + else renderSession.spriteBatch.renderTilingSprite(this); + + // simple render children! + for(i=0,j=this.children.length; i 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; + + var bounds = this._bounds; + + bounds.x = minX; + bounds.width = maxX - minX; + + bounds.y = minY; + bounds.height = maxY - minY; + + // store a refferance so that if this function gets called again in the render cycle we do not have to recacalculate + this._currentBounds = bounds; + + return bounds; +}; + + +PIXI.TilingSprite.prototype.generateTilingTexture = function(forcePowerOfTwo) +{ + var texture = this.texture; + + if(!texture.baseTexture.hasLoaded)return; + + var baseTexture = texture.baseTexture; + var frame = texture.frame; + + var targetWidth, targetHeight; + + // check that the frame is the same size as the base texture. + + var isFrame = frame.width !== baseTexture.width || frame.height !== baseTexture.height; + + this.tilingTexture = texture; + + var newTextureRequired = false; + + if(!forcePowerOfTwo) + { + if(isFrame) + { + targetWidth = frame.width; + targetHeight = frame.height; + + newTextureRequired = true; + } + } + else + { + targetWidth = PIXI.getNextPowerOfTwo(texture.frame.width); + targetHeight = PIXI.getNextPowerOfTwo(texture.frame.height); + + if(frame.width !== targetWidth && frame.height !== targetHeight)newTextureRequired = true; + } + + if(newTextureRequired) + { + var canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight); + + canvasBuffer.context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + targetWidth, + targetHeight); + + this.tilingTexture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this.tileScaleOffset.x = frame.width / targetWidth; + this.tileScaleOffset.y = frame.height / targetHeight; + } + + + this.tilingTexture.baseTexture._powerOf2 = true; +}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi @@ -7472,6 +8243,1350 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * */ +/* + * 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), 10); + 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) 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) 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) 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) 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, + amount; + + 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. + 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); + + 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 (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 ? this.bones[0] : 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].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 ? this.queue[this.queue.length - 1].animation : this.current; + 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) { + /*jshint -W069*/ + var skeletonData = new spine.SkeletonData(), + boneData; + + // 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"]; + } + 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 (i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + 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) { + /*jshint -W069*/ + 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) { + /*jshint -W069*/ + var timelines = []; + var duration = 0; + var frameIndex, timeline, timelineName, valueMap, values, + i, n; + + 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 (timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + values = boneMap[timelineName]; + if (timelineName == "rotate") { + timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + frameIndex = 0; + for (i = 0, n = values.length; i < n; i++) { + 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 timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + frameIndex = 0; + for (i = 0, n = values.length; i < n; i++) { + 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 (timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + values = slotMap[timelineName]; + if (timelineName == "color") { + timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + frameIndex = 0; + for (i = 0, n = values.length; i < n; i++) { + 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") { + timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + frameIndex = 0; + for (i = 0, n = values.length; i < n; i++) { + 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) { + /*jshint -W069*/ + 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) + 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], 10); + var y = parseInt(tuple[1], 10); + + reader.readTuple(tuple); + var width = parseInt(tuple[0], 10); + var height = parseInt(tuple[1], 10); + + 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], 10), parseInt(tuple[1], 10), parseInt(tuple[2], 10), parseInt(tuple[3], 10)]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0], 10), parseInt(tuple[1], 10), parseInt(tuple[2], 10), parseInt(tuple[3], 10)]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0], 10); + region.originalHeight = parseInt(tuple[1], 10); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0], 10); + region.offsetY = parseInt(tuple[1], 10); + + region.index = parseInt(reader.readValue(), 10); + + 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) 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; + } +} + +spine.Bone.yDown = true; +PIXI.AnimCache = {}; + /** * 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 @@ -7483,37 +9598,37 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @param url {String} The url of the spine anim file to be used */ PIXI.Spine = function (url) { - PIXI.DisplayObjectContainer.call(this); + PIXI.DisplayObjectContainer.call(this); - this.spineData = PIXI.AnimCache[url]; + this.spineData = PIXI.AnimCache[url]; - if (!this.spineData) { - throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + 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.skeleton = new spine.Skeleton(this.spineData); + this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); + this.stateData = new spine.AnimationStateData(this.spineData); + this.state = new spine.AnimationState(this.stateData); - this.slotContainers = []; + 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); - } + 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); @@ -7526,1461 +9641,68 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @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(); + 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; - } + 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; + 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; + 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.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); - } + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } - PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); + 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; + 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; + 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 ); - -} - -// 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 */ @@ -8997,85 +9719,99 @@ PIXI.texturesToDestroy = []; * @constructor * @param source {String} the source object (image or canvas) */ -PIXI.BaseTexture = function(source) +PIXI.BaseTexture = function(source, scaleMode) { - PIXI.EventTarget.call( this ); + 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 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] 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 scale mode to apply when scaling this texture + * @property scaleMode + * @type PIXI.BaseTexture.SCALE_MODE + * @default PIXI.BaseTexture.SCALE_MODE.LINEAR + */ + this.scaleMode = scaleMode || PIXI.BaseTexture.SCALE_MODE.DEFAULT; - /** - * The source that is loaded to create the texture - * - * @property source - * @type Image - */ - this.source = source; + /** + * [read-only] Describes if the base texture has loaded or not + * + * @property hasLoaded + * @type Boolean + * @readOnly + */ + this.hasLoaded = false; - if(!source)return; + /** + * The source that is loaded to create the texture + * + * @property source + * @type Image + */ + this.source = source; - 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); - } + if(!source)return; - this._powerOf2 = false; -} + 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.imageUrl = null; + this._powerOf2 = false; + + + // used for webGL + this._glTextures = []; + +}; PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; @@ -9086,13 +9822,29 @@ PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; */ PIXI.BaseTexture.prototype.destroy = function() { - if(this.source instanceof Image) - { - this.source.src = null; - } - this.source = null; - PIXI.texturesToDestroy.push(this); -} + if(this.source instanceof Image) + { + if (this.imageUrl in PIXI.BaseTextureCache) + delete PIXI.BaseTextureCache[this.imageUrl]; + this.imageUrl = null; + this.source.src = null; + } + this.source = null; + PIXI.texturesToDestroy.push(this); +}; + +/** + * + * + * @method destroy + */ + +PIXI.BaseTexture.prototype.updateSourceImage = function(newSrc) +{ + this.hasLoaded = false; + this.source.src = null; + this.source.src = newSrc; +}; /** * Helper function that returns a base texture based on an image url @@ -9103,26 +9855,32 @@ PIXI.BaseTexture.prototype.destroy = function() * @param imageUrl {String} The image url of the texture * @return BaseTexture */ -PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) +PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin, scaleMode) { - 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; - } + 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, scaleMode); + baseTexture.imageUrl = imageUrl; + PIXI.BaseTextureCache[imageUrl] = baseTexture; + } - return baseTexture; -} + return baseTexture; +}; +PIXI.BaseTexture.SCALE_MODE = { + DEFAULT: 0, //default to LINEAR + LINEAR: 0, + NEAREST: 1 +}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -9138,60 +9896,59 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { - PIXI.EventTarget.call( this ); + PIXI.EventTarget.call( this ); - if(!frame) - { - this.noFrame = true; - frame = new PIXI.Rectangle(0,0,1,1); - } + if(!frame) + { + this.noFrame = true; + frame = new PIXI.Rectangle(0,0,1,1); + } - if(baseTexture instanceof PIXI.Texture) - baseTexture = baseTexture.baseTexture; + if(baseTexture instanceof PIXI.Texture) + baseTexture = baseTexture.baseTexture; - /** - * The base texture of this texture - * - * @property baseTexture - * @type BaseTexture - */ - this.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 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(); + /** + * The trim point + * + * @property trim + * @type Point + */ + this.trim = new PIXI.Point(); - this.scope = this; + 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()} ); - } -} + if(baseTexture.hasLoaded) + { + if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + + this.setFrame(frame); + } + else + { + var scope = this; + baseTexture.addEventListener('loaded', function(){ scope.onBaseTextureLoaded(); }); + } +}; PIXI.Texture.prototype.constructor = PIXI.Texture; @@ -9202,18 +9959,17 @@ PIXI.Texture.prototype.constructor = PIXI.Texture; * @param event * @private */ -PIXI.Texture.prototype.onBaseTextureLoaded = function(event) +PIXI.Texture.prototype.onBaseTextureLoaded = function() { - var baseTexture = this.baseTexture; - baseTexture.removeEventListener( 'loaded', this.onLoaded ); + 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; + if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + + this.setFrame(this.frame); - this.scope.dispatchEvent( { type: 'update', content: this } ); -} + this.scope.dispatchEvent( { type: 'update', content: this } ); +}; /** * Destroys this texture @@ -9223,8 +9979,8 @@ PIXI.Texture.prototype.onBaseTextureLoaded = function(event) */ PIXI.Texture.prototype.destroy = function(destroyBase) { - if(destroyBase)this.baseTexture.destroy(); -} + if(destroyBase) this.baseTexture.destroy(); +}; /** * Specifies the rectangle region of the baseTexture @@ -9234,20 +9990,41 @@ PIXI.Texture.prototype.destroy = function(destroyBase) */ PIXI.Texture.prototype.setFrame = function(frame) { - this.frame = frame; - this.width = frame.width; - this.height = frame.height; + 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); - } + 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; + this.updateFrame = true; - PIXI.Texture.frameUpdates.push(this); - //this.dispatchEvent( { type: 'update', content: this } ); -} + PIXI.Texture.frameUpdates.push(this); + //this.dispatchEvent( { type: 'update', content: this } ); +}; + +PIXI.Texture.prototype._updateWebGLuvs = function() +{ + if(!this._uvs)this._uvs = new Float32Array(8); + + var frame = this.frame; + var tw = this.baseTexture.width; + var th = this.baseTexture.height; + + this._uvs[0] = frame.x / tw; + this._uvs[1] = frame.y / th; + + this._uvs[2] = (frame.x + frame.width) / tw; + this._uvs[3] = frame.y / th; + + this._uvs[4] = (frame.x + frame.width) / tw; + this._uvs[5] = (frame.y + frame.height) / th; + + this._uvs[6] = frame.x / tw; + this._uvs[7] = (frame.y + frame.height) / th; +}; /** * Helper function that returns a texture based on an image url @@ -9259,18 +10036,18 @@ PIXI.Texture.prototype.setFrame = function(frame) * @param crossorigin {Boolean} Whether requests should be treated as crossorigin * @return Texture */ -PIXI.Texture.fromImage = function(imageUrl, crossorigin) +PIXI.Texture.fromImage = function(imageUrl, crossorigin, scaleMode) { - var texture = PIXI.TextureCache[imageUrl]; - - if(!texture) - { - texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); - PIXI.TextureCache[imageUrl] = texture; - } - - return texture; -} + var texture = PIXI.TextureCache[imageUrl]; + + if(!texture) + { + texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin, scaleMode)); + PIXI.TextureCache[imageUrl] = texture; + } + + return texture; +}; /** * Helper function that returns a texture based on a frame id @@ -9283,10 +10060,10 @@ PIXI.Texture.fromImage = function(imageUrl, crossorigin) */ 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; -} + 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 @@ -9297,11 +10074,11 @@ PIXI.Texture.fromFrame = function(frameId) * @param canvas {Canvas} The canvas element source of the texture * @return Texture */ -PIXI.Texture.fromCanvas = function(canvas) +PIXI.Texture.fromCanvas = function(canvas, scaleMode) { - var baseTexture = new PIXI.BaseTexture(canvas); - return new PIXI.Texture(baseTexture); -} + var baseTexture = new PIXI.BaseTexture(canvas, scaleMode); + return new PIXI.Texture(baseTexture); +}; /** @@ -9314,11 +10091,11 @@ PIXI.Texture.fromCanvas = function(canvas) */ PIXI.Texture.addTextureToCache = function(texture, id) { - PIXI.TextureCache[id] = texture; -} + PIXI.TextureCache[id] = texture; +}; /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9327,14 +10104,15 @@ PIXI.Texture.addTextureToCache = function(texture, id) */ PIXI.Texture.removeTextureFromCache = function(id) { - var texture = PIXI.TextureCache[id] - PIXI.TextureCache[id] = null; - return texture; -} + var texture = PIXI.TextureCache[id]; + PIXI.TextureCache[id] = null; + return texture; +}; // this is more for webGL.. it contains updated frames.. PIXI.Texture.frameUpdates = []; +PIXI.Texture.SCALE_MODE = PIXI.BaseTexture.SCALE_MODE; /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -9343,24 +10121,24 @@ PIXI.Texture.frameUpdates = []; /** 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. - + __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); + + 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 + var doc = new PIXI.DisplayObjectContainer(); + doc.addChild(sprite); + renderTexture.render(doc); // Renders to center of renderTexture @class RenderTexture @extends Texture @@ -9368,115 +10146,74 @@ PIXI.Texture.frameUpdates = []; @param width {Number} The width of the render texture @param height {Number} The height of the render texture */ -PIXI.RenderTexture = function(width, height) +PIXI.RenderTexture = function(width, height, renderer) { - PIXI.EventTarget.call( this ); + PIXI.EventTarget.call( this ); - this.width = width || 100; - this.height = height || 100; + this.width = width || 100; + this.height = height || 100; - this.indetityMatrix = PIXI.mat3.create(); + this.indetityMatrix = PIXI.mat3.create(); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); - if(PIXI.gl) - { - this.initWebGL(); - } - else - { - this.initCanvas(); - } -} + this.baseTexture = new PIXI.BaseTexture(); + this.baseTexture.width = this.width; + this.baseTexture.height = this.height; + this.baseTexture._glTextures = []; + + this.baseTexture.hasLoaded = true; + + // each render texture can only belong to one renderer at the moment if its webGL + this.renderer = renderer || PIXI.defaultRenderer; + + if(this.renderer.type === PIXI.WEBGL_RENDERER) + { + var gl = this.renderer.gl; + + this.textureBuffer = new PIXI.FilterTexture(gl, this.width, this.height); + this.baseTexture._glTextures[gl.id] = this.textureBuffer.texture; + + this.render = this.renderWebGL; + this.projection = new PIXI.Point(this.width/2 , -this.height/2); + } + else + { + this.render = this.renderCanvas; + this.textureBuffer = new PIXI.CanvasBuffer(this.width, this.height); + this.baseTexture.source = this.textureBuffer.canvas; + } + + PIXI.Texture.frameUpdates.push(this); +}; 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; - 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); - } -} + this.frame.width = this.width; + this.frame.height = 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); + if(this.renderer.type === PIXI.WEBGL_RENDERER) + { + this.projection.x = this.width / 2; + this.projection.y = -this.height / 2; - this.baseTexture = new PIXI.BaseTexture(this.renderer.view); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + var gl = this.gl; + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTextures[gl.id]); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + else + { + this.textureBuffer.resize(this.width, this.height); + } - this.render = this.renderCanvas; -} + PIXI.Texture.frameUpdates.push(this); +}; /** * This function will draw the display object to the texture. @@ -9488,68 +10225,43 @@ PIXI.RenderTexture.prototype.initCanvas = function() */ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) { - var gl = PIXI.gl; + var gl = this.renderer.gl; - // enable the alpha color mask.. - gl.colorMask(true, true, true, true); + gl.colorMask(true, true, true, true); - gl.viewport(0, 0, this.width, this.height); + gl.viewport(0, 0, this.width, this.height); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer ); - if(clear) - { - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } + if(clear)this.textureBuffer.clear(); - // THIS WILL MESS WITH HIT TESTING! - var children = displayObject.children; + // 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; + //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". + * 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); + PIXI.EventTarget.call(this); - /** - * The array of asset URLs that are going to be loaded + /** + * The array of asset URLs that are going to be loaded * - * @property assetURLs - * @type Array - */ - this.assetURLs = assetURLs; + * @property assetURLs + * @type Array + */ + this.assetURLs = assetURLs; /** * Whether the requests should be treated as cross origin @@ -9627,7 +10338,7 @@ PIXI.AssetLoader = function(assetURLs, crossorigin) * @property crossorigin * @type Boolean */ - this.crossorigin = crossorigin; + this.crossorigin = crossorigin; /** * Maps file extension to loader types @@ -9636,17 +10347,16 @@ PIXI.AssetLoader = function(assetURLs, crossorigin) * @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 + 'jpg': PIXI.ImageLoader, + 'jpeg': PIXI.ImageLoader, + 'png': PIXI.ImageLoader, + 'gif': PIXI.ImageLoader, + 'json': PIXI.JsonLoader, + 'atlas': PIXI.AtlasLoader, + 'anim': PIXI.SpineLoader, + 'xml': PIXI.BitmapFontLoader, + 'fnt': PIXI.BitmapFontLoader }; - - }; /** @@ -9656,12 +10366,40 @@ PIXI.AssetLoader = function(assetURLs, crossorigin) /** * Fired when all the assets have loaded - * @event onComplete + * @event onComplete */ // constructor PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; + +PIXI.AssetLoader.prototype._getDataType = function(str) +{ + var test = 'data:'; + //starts with 'data:' + var start = str.slice(0, test.length).toLowerCase(); + if (start === test) { + var data = str.slice(test.length); + + var sepIdx = data.indexOf(','); + if (sepIdx === -1) //malformed data URI scheme + return null; + + //e.g. 'image/gif;base64' => 'image/gif' + var info = data.slice(0, sepIdx).split(';')[0]; + + //We might need to handle some special cases here... + //standardize text/plain to 'txt' file extension + if (!info || info.toLowerCase() === 'text/plain') + return 'txt'; + + //User specified mime type, try splitting it by '/' + return info.split('/').pop().toLowerCase(); + } + + return null; +}; + /** * Starts loading the assets sequentially * @@ -9671,25 +10409,31 @@ PIXI.AssetLoader.prototype.load = function() { var scope = this; - this.loadCount = this.assetURLs.length; + function onLoad() { + scope.onAssetLoaded(); + } + + 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 fileName = this.assetURLs[i]; + //first see if we have a data URI scheme.. + var fileType = this._getDataType(fileName); - var loaderClass = this.loadersByType[fileType]; - if(!loaderClass) - throw new Error(fileType + " is an unsupported file type"); + //if not, assume it's a file URI + if (!fileType) + fileType = fileName.split('?').shift().split('.').pop().toLowerCase(); - var loader = new loaderClass(fileName, this.crossorigin); + var Constructor = this.loadersByType[fileType]; + if(!Constructor) + throw new Error(fileType + ' is an unsupported file type'); - loader.addEventListener("loaded", function() - { - scope.onAssetLoaded(); - }); + var loader = new Constructor(fileName, this.crossorigin); + + loader.addEventListener('loaded', onLoad); loader.load(); - } + } }; /** @@ -9701,16 +10445,15 @@ PIXI.AssetLoader.prototype.load = function() 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(); - } -}; + this.dispatchEvent({type: 'onProgress', content: this}); + if (this.onProgress) this.onProgress(); + if (!this.loadCount) + { + this.dispatchEvent({type: 'onComplete', content: this}); + if(this.onComplete) this.onComplete(); + } +}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -9718,8 +10461,8 @@ PIXI.AssetLoader.prototype.onAssetLoaded = function() /** * 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 + * When loaded this class will dispatch a 'loaded' event + * If load failed this class will dispatch a 'error' event * * @class JsonLoader * @uses EventTarget @@ -9728,42 +10471,42 @@ PIXI.AssetLoader.prototype.onAssetLoaded = function() * @param crossorigin {Boolean} Whether requests should be treated as crossorigin */ PIXI.JsonLoader = function (url, crossorigin) { - PIXI.EventTarget.call(this); + PIXI.EventTarget.call(this); - /** - * The url of the bitmap font data - * - * @property url - * @type String - */ - this.url = url; + /** + * 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; + /** + * 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] 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; - /** - * [read-only] Whether the data has loaded yet - * - * @property loaded - * @type Boolean - * @readOnly - */ - this.loaded = false; - }; // constructor @@ -9775,15 +10518,15 @@ PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; * @method load */ PIXI.JsonLoader.prototype.load = function () { - this.ajaxRequest = new AjaxRequest(); - var scope = this; - this.ajaxRequest.onreadystatechange = function () { - scope.onJSONLoaded(); - }; + this.ajaxRequest = new PIXI.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); + this.ajaxRequest.open('GET', this.url, true); + if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType('application/json'); + this.ajaxRequest.send(null); }; /** @@ -9793,62 +10536,72 @@ PIXI.JsonLoader.prototype.load = function () { * @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(); - } - } + if (this.ajaxRequest.readyState === 4) { + if (this.ajaxRequest.status === 200 || window.location.protocol.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() { + 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 + }); + + // check to see ifthe sprite ha been trimmed.. + if (frameData[i].trimmed) { + + var texture = PIXI.TextureCache[i]; + + texture.trimmed = true; + + var actualSize = frameData[i].sourceSize; + var realSize = frameData[i].spriteSourceSize; + + texture.trim.x = realSize.x; + texture.trim.y = realSize.y; + texture.trim.realWidth = actualSize.w; + texture.trim.realHeight = actualSize.h; + } + } + } + + 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(); + } + } }; /** @@ -9858,11 +10611,11 @@ PIXI.JsonLoader.prototype.onJSONLoaded = function () { * @private */ PIXI.JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: "loaded", - content: this - }); + this.loaded = true; + this.dispatchEvent({ + type: 'loaded', + content: this + }); }; /** @@ -9872,23 +10625,208 @@ PIXI.JsonLoader.prototype.onLoaded = function () { * @private */ PIXI.JsonLoader.prototype.onError = function () { - this.dispatchEvent({ - type: "error", - content: this - }); + this.dispatchEvent({ + type: 'error', + content: this + }); }; +/** + * @author Martin Kelm http://mkelm.github.com + */ + +/** + * The atlas file loader is used to load in Atlas data and parsing it + * When loaded this class will dispatch a 'loaded' event + * If load failed this class will dispatch a 'error' event + * @class AtlasLoader + * @extends EventTarget + * @constructor + * @param {String} url the url of the JSON file + * @param {Boolean} crossorigin + */ + +PIXI.AtlasLoader = function (url, crossorigin) { + PIXI.EventTarget.call(this); + this.url = url; + this.baseUrl = url.replace(/[^\/]*$/, ''); + this.crossorigin = crossorigin; + this.loaded = false; + +}; + +// constructor +PIXI.AtlasLoader.constructor = PIXI.AtlasLoader; + +/** + * This will begin loading the JSON file + */ +PIXI.AtlasLoader.prototype.load = function () { + this.ajaxRequest = new PIXI.AjaxRequest(); + this.ajaxRequest.onreadystatechange = this.onAtlasLoaded.bind(this); + + 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 + * @private + */ +PIXI.AtlasLoader.prototype.onAtlasLoaded = function () { + if (this.ajaxRequest.readyState === 4) { + if (this.ajaxRequest.status === 200 || window.location.href.indexOf('http') === -1) { + this.atlas = { + meta : { + image : [] + }, + frames : [] + }; + var result = this.ajaxRequest.responseText.split(/\r?\n/); + var lineCount = -3; + + var currentImageId = 0; + var currentFrame = null; + var nameInNextLine = false; + + var i = 0, + j = 0, + selfOnLoaded = this.onLoaded.bind(this); + + // parser without rotation support yet! + for (i = 0; i < result.length; i++) { + result[i] = result[i].replace(/^\s+|\s+$/g, ''); + if (result[i] === '') { + nameInNextLine = i+1; + } + if (result[i].length > 0) { + if (nameInNextLine === i) { + this.atlas.meta.image.push(result[i]); + currentImageId = this.atlas.meta.image.length - 1; + this.atlas.frames.push({}); + lineCount = -3; + } else if (lineCount > 0) { + if (lineCount % 7 === 1) { // frame name + if (currentFrame != null) { //jshint ignore:line + this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; + } + currentFrame = { name: result[i], frame : {} }; + } else { + var text = result[i].split(' '); + if (lineCount % 7 === 3) { // position + currentFrame.frame.x = Number(text[1].replace(',', '')); + currentFrame.frame.y = Number(text[2]); + } else if (lineCount % 7 === 4) { // size + currentFrame.frame.w = Number(text[1].replace(',', '')); + currentFrame.frame.h = Number(text[2]); + } else if (lineCount % 7 === 5) { // real size + var realSize = { + x : 0, + y : 0, + w : Number(text[1].replace(',', '')), + h : Number(text[2]) + }; + + if (realSize.w > currentFrame.frame.w || realSize.h > currentFrame.frame.h) { + currentFrame.trimmed = true; + currentFrame.realSize = realSize; + } else { + currentFrame.trimmed = false; + } + } + } + } + lineCount++; + } + } + + if (currentFrame != null) { //jshint ignore:line + this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; + } + + if (this.atlas.meta.image.length > 0) { + this.images = []; + for (j = 0; j < this.atlas.meta.image.length; j++) { + // sprite sheet + var textureUrl = this.baseUrl + this.atlas.meta.image[j]; + var frameData = this.atlas.frames[j]; + this.images.push(new PIXI.ImageLoader(textureUrl, this.crossorigin)); + + for (i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.images[j].texture.baseTexture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + PIXI.TextureCache[i].realSize = frameData[i].realSize; + // trim in pixi not supported yet, todo update trim properties if it is done ... + PIXI.TextureCache[i].trim.x = 0; + PIXI.TextureCache[i].trim.y = 0; + } + } + } + } + + this.currentImageId = 0; + for (j = 0; j < this.images.length; j++) { + this.images[j].addEventListener('loaded', selfOnLoaded); + } + this.images[this.currentImageId].load(); + + } else { + this.onLoaded(); + } + + } else { + this.onError(); + } + } +}; + +/** + * Invoke when json file loaded + * @private + */ +PIXI.AtlasLoader.prototype.onLoaded = function () { + if (this.images.length - 1 > this.currentImageId) { + this.currentImageId++; + this.images[this.currentImageId].load(); + } else { + this.loaded = true; + this.dispatchEvent({ + type: 'loaded', + content: this + }); + } +}; + +/** + * Invoke when error occured + * @private + */ +PIXI.AtlasLoader.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 + * 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. + * 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 + * When loaded this class will dispatch a 'loaded' event * * @class SpriteSheetLoader * @uses EventTarget @@ -9896,210 +10834,11 @@ PIXI.JsonLoader.prototype.onError = function () { * @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); -}; - -// 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}); -}; - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The xml loader is used to load in XML bitmap font data ("xml" or "fnt") - * To generate the data you can use http://www.angelcode.com/products/bmfont/ - * This loader will also load the image file as the data. - * When loaded this class will dispatch a "loaded" event - * - * @class BitmapFontLoader - * @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.BitmapFontLoader = function(url, crossorigin) -{ /* * i use texture packer to load the assets.. * http://www.codeandweb.com/texturepacker - * make sure to set the format as "JSON" + * make sure to set the format as 'JSON' */ PIXI.EventTarget.call(this); @@ -10126,7 +10865,220 @@ PIXI.BitmapFontLoader = function(url, crossorigin) * @type String * @readOnly */ - this.baseUrl = url.replace(/[^\/]*$/, ""); + 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.onLoaded(); + }); + jsonLoader.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},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){this._mask=a,a?this.addFilter(a):this.removeFilter()}}),f.DisplayObject.prototype.addFilter=function(a){if(!this.filter){this.filter=!0;var b=new f.FilterBlock,c=new f.FilterBlock;b.mask=a,c.mask=a,b.first=b.last=this,c.first=c.last=this,b.open=!0;var d,e,g=b,h=b;e=this.first._iPrev,e?(d=e._iNext,g._iPrev=e,e._iNext=g):d=this,d&&(d._iPrev=h,h._iNext=d);var g=c,h=c,d=null,e=null;e=this.last,d=e._iNext,d&&(d._iPrev=h,h._iNext=d),g._iPrev=e,e._iNext=g;for(var i=this,j=this.last;i;)i.last==j&&(i.last=c),i=i.parent;this.first=b,this.__renderGroup&&this.__renderGroup.addFilterBlocks(b,c),a.renderable=!1}},f.DisplayObject.prototype.removeFilter=function(){if(this.filter){this.filter=!1;var a=this.first,b=a._iNext,c=a._iPrev;b&&(b._iPrev=c),c&&(c._iNext=b),this.first=a._iNext;var d=this.last,b=d._iNext,c=d._iPrev;b&&(b._iPrev=c),c._iNext=b;for(var e=d._iPrev,f=this;f.last==d&&(f.last=e,f=f.parent););var g=a.mask;g.renderable=!0,this.__renderGroup&&this.__renderGroup.removeFilterBlocks(a,d)}},f.DisplayObject.prototype.updateTransform=function(){this.rotation!==this.rotationCache&&(this.rotationCache=this.rotation,this._sr=Math.sin(this.rotation),this._cr=Math.cos(this.rotation));var a=this.localTransform,b=this.parent.worldTransform,c=this.worldTransform;a[0]=this._cr*this.scale.x,a[1]=-this._sr*this.scale.y,a[3]=this._sr*this.scale.x,a[4]=this._cr*this.scale.y;var d=this.pivot.x,e=this.pivot.y,g=a[0],h=a[1],i=this.position.x-a[0]*d-e*a[1],j=a[3],k=a[4],l=this.position.y-a[4]*e-d*a[3],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5];a[2]=i,a[5]=l,c[0]=m*g+n*j,c[1]=m*h+n*k,c[2]=m*i+n*l+o,c[3]=p*g+q*j,c[4]=p*h+q*k,c[5]=p*i+q*l+r,this.worldAlpha=this.alpha*this.parent.worldAlpha,this.vcount=f.visibleCount},f.visibleCount=0,f.DisplayObjectContainer=function(){f.DisplayObject.call(this),this.children=[]},f.DisplayObjectContainer.prototype=Object.create(f.DisplayObject.prototype),f.DisplayObjectContainer.prototype.constructor=f.DisplayObjectContainer,f.DisplayObjectContainer.prototype.addChild=function(a){if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.children.push(a),this.stage){var b=a;do b.interactive&&(this.stage.dirty=!0),b.stage=this.stage,b=b._iNext;while(b)}var c,d,e=a.first,f=a.last;d=this.filter?this.last._iPrev:this.last,c=d._iNext;for(var g=this,h=d;g;)g.last==h&&(g.last=a.last),g=g.parent;c&&(c._iPrev=f,f._iNext=c),e._iPrev=d,d._iNext=e,this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.addChildAt=function(a,b){if(!(b>=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,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(a){this.graphics=a,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.Sprite.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?f:arguments.callee(a,b,f,d,e):arguments.callee(a,b,c,f,e)},c=function(a,c,d){if(a.measureText(c).width<=d||c.length<1)return c;var e=b(a,c,0,c.length,d);return c.substring(0,e)+"\n"+arguments.callee(a,c.substring(e),d)},d="",e=a.split("\n"),f=0;f=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.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){window.navigator.msPointerEnabled&&(a.view.style["-ms-content-zooming"]="none",a.view.style["-ms-touch-action"]="none"),this.target=a,a.view.addEventListener("mousemove",this.onMouseMove.bind(this),!0),a.view.addEventListener("mousedown",this.onMouseDown.bind(this),!0),document.body.addEventListener("mouseup",this.onMouseUp.bind(this),!0),a.view.addEventListener("mouseout",this.onMouseOut.bind(this),!0),a.view.addEventListener("touchstart",this.onTouchStart.bind(this),!0),a.view.addEventListener("touchend",this.onTouchEnd.bind(this),!0),a.view.addEventListener("touchmove",this.onTouchMove.bind(this),!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.target.view.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.target.view.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.target.view.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.target.view.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.target.view.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.target.view.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.target.view.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,b){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=b,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.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){for(var c in a[b.type])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{return!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch(a){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.shaderFragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * vColor;","}"],f.shaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.stripShaderFragmentSrc=["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;","}"],f.stripShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.primitiveShaderFragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],f.primitiveShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"],f.initPrimitiveShader=function(){var a=f.gl,b=f.compileProgram(f.primitiveShaderVertexSrc,f.primitiveShaderFragmentSrc);a.useProgram(b),b.vertexPositionAttribute=a.getAttribLocation(b,"aVertexPosition"),b.colorAttribute=a.getAttribLocation(b,"aColor"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.translationMatrix=a.getUniformLocation(b,"translationMatrix"),b.alpha=a.getUniformLocation(b,"alpha"),f.primitiveProgram=b},f.initDefaultShader=function(){var a=this.gl,b=f.compileProgram(f.shaderVertexSrc,f.shaderFragmentSrc);a.useProgram(b),b.vertexPositionAttribute=a.getAttribLocation(b,"aVertexPosition"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.textureCoordAttribute=a.getAttribLocation(b,"aTextureCoord"),b.colorAttribute=a.getAttribLocation(b,"aColor"),b.samplerUniform=a.getUniformLocation(b,"uSampler"),f.shaderProgram=b},f.initDefaultStripShader=function(){var a=this.gl,b=f.compileProgram(f.stripShaderVertexSrc,f.stripShaderFragmentSrc);a.useProgram(b),b.vertexPositionAttribute=a.getAttribLocation(b,"aVertexPosition"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.textureCoordAttribute=a.getAttribLocation(b,"aTextureCoord"),b.translationMatrix=a.getUniformLocation(b,"translationMatrix"),b.alpha=a.getUniformLocation(b,"alpha"),b.colorAttribute=a.getAttribLocation(b,"aColor"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.samplerUniform=a.getUniformLocation(b,"uSampler"),f.stripShaderProgram=b},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:(alert(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)||alert("Could not initialise shaders"),g},f.activateDefaultShader=function(){var a=f.gl,b=f.shaderProgram; -a.useProgram(b),a.enableVertexAttribArray(b.vertexPositionAttribute),a.enableVertexAttribArray(b.textureCoordAttribute),a.enableVertexAttribArray(b.colorAttribute)},f.activatePrimitiveShader=function(){var a=f.gl;a.disableVertexAttribArray(f.shaderProgram.textureCoordAttribute),a.disableVertexAttribArray(f.shaderProgram.colorAttribute),a.useProgram(f.primitiveProgram),a.enableVertexAttribArray(f.primitiveProgram.vertexPositionAttribute),a.enableVertexAttribArray(f.primitiveProgram.colorAttribute)},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.primitiveProgram.translationMatrix,!1,d),c.uniform2f(f.primitiveProgram.projectionVector,b.x,b.y),c.uniform1f(f.primitiveProgram.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.shaderProgram.vertexPositionAttribute,2,c.FLOAT,!1,0,0),c.vertexAttribPointer(f.primitiveProgram.vertexPositionAttribute,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveProgram.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.activateDefaultShader()},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){var e=new f.Point(c[0],c[1]),g=new f.Point(c[c.length-2],c[c.length-1]);if(e.x==g.x&&e.y==g.y){c.pop(),c.pop(),g=new f.Point(c[c.length-2],c[c.length-1]);var h=g.x+.5*(e.x-g.x),i=g.y+.5*(e.y-g.y);c.unshift(h,i),c.push(h,i)}var j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=b.points,F=b.indices,G=c.length/2,H=c.length,I=E.length/6,J=a.lineWidth/2,K=d(a.lineColor),L=a.lineAlpha,M=K[0]*L,N=K[1]*L,O=K[2]*L;j=c[0],k=c[1],l=c[2],m=c[3],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,E.push(j-p,k-q,M,N,O,L),E.push(j+p,k+q,M,N,O,L);for(var P=1;G-1>P;P++)j=c[2*(P-1)],k=c[2*(P-1)+1],l=c[2*P],m=c[2*P+1],n=c[2*(P+1)],o=c[2*(P+1)+1],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,r=-(m-o),s=l-n,D=Math.sqrt(r*r+s*s),r/=D,s/=D,r*=J,s*=J,v=-q+k-(-q+m),w=-p+l-(-p+j),x=(-p+j)*(-q+m)-(-p+l)*(-q+k),y=-s+o-(-s+m),z=-r+l-(-r+n),A=(-r+n)*(-s+m)-(-r+l)*(-s+o),B=v*z-y*w,0==B&&(B+=1),px=(w*A-z*x)/B,py=(y*x-v*A)/B,C=(px-l)*(px-l)+(py-m)+(py-m),C>19600?(t=p-r,u=q-s,D=Math.sqrt(t*t+u*u),t/=D,u/=D,t*=J,u*=J,E.push(l-t,m-u),E.push(M,N,O,L),E.push(l+t,m+u),E.push(M,N,O,L),E.push(l-t,m-u),E.push(M,N,O,L),H++):(E.push(px,py),E.push(M,N,O,L),E.push(l-(px-l),m-(py-m)),E.push(M,N,O,L));j=c[2*(G-2)],k=c[2*(G-2)+1],l=c[2*(G-1)],m=c[2*(G-1)+1],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,E.push(l-p,m-q),E.push(M,N,O,L),E.push(l+p,m+q),E.push(M,N,O,L),F.push(I);for(var P=0;H>P;P++)F.push(I++);F.push(I-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=[];try{f.gl=this.gl=this.view.getContext("experimental-webgl",{alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0})}catch(h){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}f.initPrimitiveShader(),f.initDefaultShader(),f.initDefaultStripShader(),f.activateDefaultShader();var i=this.gl;f.WebGLRenderer.gl=i,this.batch=new f.WebGLBatch(i),i.disable(i.DEPTH_TEST),i.disable(i.CULL_FACE),i.enable(i.BLEND),i.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new f.WebGLRenderGroup(this.gl)},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,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.dynamicSize0;)n=n.children[n.children.length-1],n.renderable&&(m=n);if(m instanceof f.Sprite){l=m.batch;var k=l.head;if(k==m)g=0;else for(g=1;k.__next!=m;)g++,k=k.__next}else l=m;if(j==l)return j instanceof f.WebGLBatch?j.render(d,g+1):this.renderSpecial(j,b),void 0;e=this.batchs.indexOf(j),h=this.batchs.indexOf(l),j instanceof f.WebGLBatch?j.render(d):this.renderSpecial(j,b);for(var o=e+1;h>o;o++)renderable=this.batchs[o],renderable instanceof f.WebGLBatch?this.batchs[o].render():this.renderSpecial(renderable,b);l instanceof f.WebGLBatch?l.render(0,g+1):this.renderSpecial(l,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){var c=a.vcount===f.visibleCount;if(a instanceof f.TilingSprite)c&&this.renderTilingSprite(a,b);else if(a instanceof f.Strip)c&&this.renderStrip(a,b);else if(a instanceof f.CustomRenderable)c&&a.renderWebGL(this,b);else if(a instanceof f.Graphics)c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b);else if(a instanceof f.FilterBlock){var d=f.gl;a.open?(d.enable(d.STENCIL_TEST),d.colorMask(!1,!1,!1,!1),d.stencilFunc(d.ALWAYS,1,255),d.stencilOp(d.KEEP,d.KEEP,d.REPLACE),f.WebGLGraphics.renderGraphics(a.mask,b),d.colorMask(!0,!0,!0,!0),d.stencilFunc(d.NOTEQUAL,0,255),d.stencilOp(d.KEEP,d.KEEP,d.KEEP)):d.disable(d.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&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root&&(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,d=f.shaderProgram;c.useProgram(f.stripShaderProgram);var e=f.mat3.clone(a.worldTransform);f.mat3.transpose(e),c.uniformMatrix3fv(f.stripShaderProgram.translationMatrix,!1,e),c.uniform2f(f.stripShaderProgram.projectionVector,b.x,b.y),c.uniform1f(f.stripShaderProgram.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.vertexPositionAttribute,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.textureCoordAttribute,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.vertexPositionAttribute,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.textureCoordAttribute,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),c.useProgram(f.shaderProgram)},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.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&&(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)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)if(a.open){c.save();var g=a.mask.alpha,h=a.mask.worldTransform;c.setTransform(h[0],h[3],h[1],h[4],h[2],h[5]),a.mask.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(a.mask,c),c.clip(),a.mask.worldAlpha=g}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;hh;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 l.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new l.AnimationStateData(this.spineData),this.state=new l.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 l.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 l.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 l={};l.BoneData=function(a,b){this.name=a,this.parent=b},l.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},l.SlotData=function(a,b){this.name=a,this.boneData=b},l.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},l.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},l.Bone.yDown=!1,l.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),l.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}},l.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},l.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}}},l.Skin=function(a){this.name=a,this.attachments={}},l.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)}}}},l.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},l.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)}},l.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}},l.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},l.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},l.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)}},l.RotateTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=2*a},l.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=l.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}}},l.TranslateTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=3*a},l.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=l.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}}},l.ScaleTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=3*a},l.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=l.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}}},l.ColorTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=5*a},l.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=l.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],m=d[g],n=1-(b-m)/(d[g-5]-m);n=this.curves.getCurvePercent(g/5-1,n);var o=h+(d[g+1]-h)*n,p=i+(d[g+2]-i)*n,q=j+(d[g+3]-j)*n,r=k+(d[g+4]-k)*n;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)}}},l.AttachmentTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},l.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:l.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},l.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},l.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}},l.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 l.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 l.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},l.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}},l.AttachmentType={region:0},l.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},l.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}},l.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},l.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}},l.AnimationState=function(a){this.data=a,this.queue=[]},l.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}},l.SkeletonJson=function(a){this.attachmentLoader=a},l.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new l.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 l.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 l.SlotData(j.name,h),m=j.color;m&&(k.r=l.SkeletonJson.toColor(m,0),k.g=l.SkeletonJson.toColor(m,1),k.b=l.SkeletonJson.toColor(m,2),k.a=l.SkeletonJson.toColor(m,3)),k.attachmentName=j.attachment,b.slots.push(k)}var n=a.skins;for(var o in n)if(n.hasOwnProperty(o)){var p=n[o],q=new l.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=l.AttachmentType[c.type||"region"];if(d==l.AttachmentType.region){var e=new l.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 m=new l.RotateTimeline(k.length);m.boneIndex=h;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o];m.setFrame(n,q.time,q.angle),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[2*m.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var m,r=1;"scale"==j?m=new l.ScaleTimeline(k.length):(m=new l.TranslateTimeline(k.length),r=this.scale),m.boneIndex=h;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;m.setFrame(n,q.time,s,t),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[3*m.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 m=new l.ColorTimeline(k.length);m.slotIndex=x;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=l.SkeletonJson.toColor(y,0),A=l.SkeletonJson.toColor(y,1),B=l.SkeletonJson.toColor(y,2),C=l.SkeletonJson.toColor(y,3);m.setFrame(n,q.time,z,A,B,C),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[5*m.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var m=new l.AttachmentTimeline(k.length);m.slotIndex=x;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o];m.setFrame(n++,q.time,q.name)}d.push(m),e=Math.max(e,m.frames[m.getFrameCount()-1])}}}c.animations.push(new l.Animation(a,d,e))}},l.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]))},l.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},l.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new l.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 l.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 l.AtlasPage,e.name=f,e.format=l.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=l.Atlas.TextureFilter[d[0]],e.magFilter=l.Atlas.TextureFilter[d[1]];var m=c.readValue();e.uWrap=l.Atlas.TextureWrap.clampToEdge,e.vWrap=l.Atlas.TextureWrap.clampToEdge,"x"==m?e.uWrap=l.Atlas.TextureWrap.repeat:"y"==m?e.vWrap=l.Atlas.TextureWrap.repeat:"xy"==m&&(e.uWrap=e.vWrap=l.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},l.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))}}},l.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},l.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},l.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},l.AtlasPage=function(){},l.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},l.AtlasRegion=function(){},l.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},l.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},l.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}},l.AtlasAttachmentLoader=function(a){this.atlas=a},l.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case l.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new l.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={},l.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this)},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):j.renderSpecific(a,this.projection):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection)),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;b