diff --git a/demo/dev.html b/demo/dev.html
index 54ac8da0..98267ad5 100644
--- a/demo/dev.html
+++ b/demo/dev.html
@@ -10,7 +10,7 @@
-
+
diff --git a/demo/index.html b/demo/index.html
index 1801e91a..f3bb382d 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/demo/js/lib/pixi.dev.js b/demo/js/lib/pixi.dev.js
deleted file mode 100644
index c7dd1268..00000000
--- a/demo/js/lib/pixi.dev.js
+++ /dev/null
@@ -1,14221 +0,0 @@
-/**
- * @license
- * pixi.js - v1.5.1
- * Copyright (c) 2012-2014, Mat Groves
- * http://goodboydigital.com/
- *
- * Compiled: 2014-02-13
- *
- * pixi.js is licensed under the MIT License.
- * http://www.opensource.org/licenses/mit-license.php
- */
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-(function(){
-
- var root = this;
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * @module PIXI
- */
-var PIXI = PIXI || {};
-
-/*
-*
-* This file contains a lot of pixi consts which are used across the rendering engine
-* @class Consts
-*/
-PIXI.WEBGL_RENDERER = 0;
-PIXI.CANVAS_RENDERER = 1;
-
-// useful for testing against if your lib is using pixi.
-PIXI.VERSION = "v1.5.1";
-
-// the various blend modes supported by pixi
-PIXI.blendModes = {
- NORMAL:0,
- ADD:1,
- MULTIPLY:2,
- SCREEN:3,
- OVERLAY:4,
- DARKEN:5,
- LIGHTEN:6,
- COLOR_DODGE:7,
- COLOR_BURN:8,
- HARD_LIGHT:9,
- SOFT_LIGHT:10,
- DIFFERENCE:11,
- EXCLUSION:12,
- HUE:13,
- SATURATION:14,
- COLOR:15,
- LUMINOSITY:16
-};
-
-// the scale modes
-PIXI.scaleModes = {
- DEFAULT:0,
- LINEAR:0,
- NEAREST:1
-};
-
-// interaction frequency
-PIXI.INTERACTION_FREQUENCY = 30;
-PIXI.AUTO_PREVENT_DEFAULT = true;
-
-PIXI.RAD_TO_DEG = 180 / Math.PI;
-PIXI.DEG_TO_RAD = Math.PI / 180;
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis.
- *
- * @class Point
- * @constructor
- * @param x {Number} position of the point on the x axis
- * @param y {Number} position of the point on the y axis
- */
-PIXI.Point = function(x, y)
-{
- /**
- * @property x
- * @type Number
- * @default 0
- */
- this.x = x || 0;
-
- /**
- * @property y
- * @type Number
- * @default 0
- */
- this.y = y || 0;
-};
-
-/**
- * Creates a clone of this point
- *
- * @method clone
- * @return {Point} a copy of the point
- */
-PIXI.Point.prototype.clone = function()
-{
- return new PIXI.Point(this.x, this.y);
-};
-
-// constructor
-PIXI.Point.prototype.constructor = PIXI.Point;
-
-PIXI.Point.prototype.set = function(x, y)
-{
- this.x = x || 0;
- this.y = y || ( (y !== 0) ? this.x : 0 ) ;
-};
-
-
-/**
- * @author Mat Groves http://matgroves.com/
- */
-
-/**
- * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height.
- *
- * @class Rectangle
- * @constructor
- * @param x {Number} The X coord of the upper-left corner of the rectangle
- * @param y {Number} The Y coord of the upper-left corner of the rectangle
- * @param width {Number} The overall width of this rectangle
- * @param height {Number} The overall height of this rectangle
- */
-PIXI.Rectangle = function(x, y, width, height)
-{
- /**
- * @property x
- * @type Number
- * @default 0
- */
- this.x = x || 0;
-
- /**
- * @property y
- * @type Number
- * @default 0
- */
- this.y = y || 0;
-
- /**
- * @property width
- * @type Number
- * @default 0
- */
- this.width = width || 0;
-
- /**
- * @property height
- * @type Number
- * @default 0
- */
- this.height = height || 0;
-};
-
-/**
- * Creates a clone of this Rectangle
- *
- * @method clone
- * @return {Rectangle} a copy of the rectangle
- */
-PIXI.Rectangle.prototype.clone = function()
-{
- return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
-};
-
-/**
- * Checks whether the x and y coordinates passed to this function are contained within this Rectangle
- *
- * @method contains
- * @param x {Number} The X coordinate of the point to test
- * @param y {Number} The Y coordinate of the point to test
- * @return {Boolean} Whether the x/y coords are within this Rectangle
- */
-PIXI.Rectangle.prototype.contains = function(x, y)
-{
- if(this.width <= 0 || this.height <= 0)
- return false;
-
- var x1 = this.x;
- if(x >= x1 && x <= x1 + this.width)
- {
- var y1 = this.y;
-
- if(y >= y1 && y <= y1 + this.height)
- {
- return true;
- }
- }
-
- return false;
-};
-
-// constructor
-PIXI.Rectangle.prototype.constructor = PIXI.Rectangle;
-
-PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0);
-/**
- * @author Adrien Brault
- */
-
-/**
- * @class Polygon
- * @constructor
- * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon,
- * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be
- * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the
- * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are
- * Numbers.
- */
-PIXI.Polygon = function(points)
-{
- //if points isn't an array, use arguments as the array
- if(!(points instanceof Array))
- points = Array.prototype.slice.call(arguments);
-
- //if this is a flat array of numbers, convert it to points
- if(typeof points[0] === 'number') {
- var p = [];
- for(var i = 0, il = points.length; i < il; i+=2) {
- p.push(
- new PIXI.Point(points[i], points[i + 1])
- );
- }
-
- points = p;
- }
-
- this.points = points;
-};
-
-/**
- * Creates a clone of this polygon
- *
- * @method clone
- * @return {Polygon} a copy of the polygon
- */
-PIXI.Polygon.prototype.clone = function()
-{
- var points = [];
- for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
-
- if(intersect) inside = !inside;
- }
-
- return inside;
-};
-
-// constructor
-PIXI.Polygon.prototype.constructor = PIXI.Polygon;
-
-/**
- * @author Chad Engler
- */
-
-/**
- * The Circle object can be used to specify a hit area for displayObjects
- *
- * @class Circle
- * @constructor
- * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this circle
- * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this circle
- * @param radius {Number} The radius of the circle
- */
-PIXI.Circle = function(x, y, radius)
-{
- /**
- * @property x
- * @type Number
- * @default 0
- */
- this.x = x || 0;
-
- /**
- * @property y
- * @type Number
- * @default 0
- */
- this.y = y || 0;
-
- /**
- * @property radius
- * @type Number
- * @default 0
- */
- this.radius = radius || 0;
-};
-
-/**
- * Creates a clone of this Circle instance
- *
- * @method clone
- * @return {Circle} a copy of the polygon
- */
-PIXI.Circle.prototype.clone = function()
-{
- return new PIXI.Circle(this.x, this.y, this.radius);
-};
-
-/**
- * Checks whether the x, and y coordinates passed to this function are contained within this circle
- *
- * @method contains
- * @param x {Number} The X coordinate of the point to test
- * @param y {Number} The Y coordinate of the point to test
- * @return {Boolean} Whether the x/y coordinates are within this polygon
- */
-PIXI.Circle.prototype.contains = function(x, y)
-{
- if(this.radius <= 0)
- return false;
-
- var dx = (this.x - x),
- dy = (this.y - y),
- r2 = this.radius * this.radius;
-
- dx *= dx;
- dy *= dy;
-
- return (dx + dy <= r2);
-};
-
-// constructor
-PIXI.Circle.prototype.constructor = PIXI.Circle;
-
-
-/**
- * @author Chad Engler
- */
-
-/**
- * The Ellipse object can be used to specify a hit area for displayObjects
- *
- * @class Ellipse
- * @constructor
- * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this ellipse
- * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this ellipse
- * @param width {Number} The overall width of this ellipse
- * @param height {Number} The overall height of this ellipse
- */
-PIXI.Ellipse = function(x, y, width, height)
-{
- /**
- * @property x
- * @type Number
- * @default 0
- */
- this.x = x || 0;
-
- /**
- * @property y
- * @type Number
- * @default 0
- */
- this.y = y || 0;
-
- /**
- * @property width
- * @type Number
- * @default 0
- */
- this.width = width || 0;
-
- /**
- * @property height
- * @type Number
- * @default 0
- */
- this.height = height || 0;
-};
-
-/**
- * Creates a clone of this Ellipse instance
- *
- * @method clone
- * @return {Ellipse} a copy of the ellipse
- */
-PIXI.Ellipse.prototype.clone = function()
-{
- return new PIXI.Ellipse(this.x, this.y, this.width, this.height);
-};
-
-/**
- * Checks whether the x and y coordinates passed to this function are contained within this ellipse
- *
- * @method contains
- * @param x {Number} The X coordinate of the point to test
- * @param y {Number} The Y coordinate of the point to test
- * @return {Boolean} Whether the x/y coords are within this ellipse
- */
-PIXI.Ellipse.prototype.contains = function(x, y)
-{
- if(this.width <= 0 || this.height <= 0)
- return false;
-
- //normalize the coords to an ellipse with center 0,0
- var normx = ((x - this.x) / this.width),
- normy = ((y - this.y) / this.height);
-
- normx *= normx;
- normy *= normy;
-
- return (normx + normy <= 1);
-};
-
-/**
-* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object
-*
-* @method getBounds
-* @return {Rectangle} the framing rectangle
-*/
-PIXI.Ellipse.prototype.getBounds = function()
-{
- return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
-};
-
-// constructor
-PIXI.Ellipse.prototype.constructor = PIXI.Ellipse;
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-PIXI.determineMatrixArrayType = function() {
- return (typeof Float32Array !== 'undefined') ? Float32Array : Array;
-};
-
-/*
-* @class Matrix2
-* The Matrix2 class will choose the best type of array to use between
-* a regular javascript Array and a Float32Array if the latter is available
-*
-*/
-PIXI.Matrix2 = PIXI.determineMatrixArrayType();
-
-/*
-* @class Matrix
-* The Matrix class is now an object, which makes it a lot faster,
-* here is a representation of it :
-* | a | b | tx|
-* | c | c | ty|
-* | 0 | 0 | 1 |
-*
-*/
-PIXI.Matrix = function()
-{
- this.a = 1;
- this.b = 0;
- this.c = 0;
- this.d = 1;
- this.tx = 0;
- this.ty = 0;
-};
-
-/**
- * Creates a pixi matrix object based on the array given as a parameter
- *
- * @method fromArray
- * @param array {Array} The array that the matrix will be filled with
- */
-PIXI.Matrix.prototype.fromArray = function(array)
-{
- this.a = array[0];
- this.b = array[1];
- this.c = array[3];
- this.d = array[4];
- this.tx = array[2];
- this.ty = array[5];
-};
-
-/**
- * Creates an array from the current Matrix object
- *
- * @method toArray
- * @param transpose {Boolean} Whether we need to transpose the matrix or not
- * @return array {Array} the newly created array which contains the matrix
- */
-PIXI.Matrix.prototype.toArray = function(transpose)
-{
- if(!this.array) this.array = new Float32Array(9);
- var array = this.array;
-
- if(transpose)
- {
- this.array[0] = this.a;
- this.array[1] = this.c;
- this.array[2] = 0;
- this.array[3] = this.b;
- this.array[4] = this.d;
- this.array[5] = 0;
- this.array[6] = this.tx;
- this.array[7] = this.ty;
- this.array[8] = 1;
- }
- else
- {
- this.array[0] = this.a;
- this.array[1] = this.b;
- this.array[2] = this.tx;
- this.array[3] = this.c;
- this.array[4] = this.d;
- this.array[5] = this.ty;
- this.array[6] = 0;
- this.array[7] = 0;
- this.array[8] = 1;
- }
-
- return array;//[this.a, this.b, this.tx, this.c, this.d, this.ty, 0, 0, 1];
-};
-
-PIXI.identityMatrix = new PIXI.Matrix();
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * The base class for all objects that are rendered on the screen.
- *
- * @class DisplayObject
- * @constructor
- */
-PIXI.DisplayObject = function()
-{
- /**
- * The coordinate of the object relative to the local coordinates of the parent.
- *
- * @property position
- * @type Point
- */
- this.position = new PIXI.Point();
-
- /**
- * The scale factor of the object.
- *
- * @property scale
- * @type Point
- */
- this.scale = new PIXI.Point(1,1);//{x:1, y:1};
-
- /**
- * The pivot point of the displayObject that it rotates around
- *
- * @property pivot
- * @type Point
- */
- this.pivot = new PIXI.Point(0,0);
-
- /**
- * The rotation of the object in radians.
- *
- * @property rotation
- * @type Number
- */
- this.rotation = 0;
-
- /**
- * The opacity of the object.
- *
- * @property alpha
- * @type Number
- */
- this.alpha = 1;
-
- /**
- * The visibility of the object.
- *
- * @property visible
- * @type Boolean
- */
- this.visible = true;
-
- /**
- * This is the defined area that will pick up mouse / touch events. It is null by default.
- * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children)
- *
- * @property hitArea
- * @type Rectangle|Circle|Ellipse|Polygon
- */
- this.hitArea = null;
-
- /**
- * This is used to indicate if the displayObject should display a mouse hand cursor on rollover
- *
- * @property buttonMode
- * @type Boolean
- */
- this.buttonMode = false;
-
- /**
- * Can this object be rendered
- *
- * @property renderable
- * @type Boolean
- */
- this.renderable = false;
-
- /**
- * [read-only] The display object container that contains this display object.
- *
- * @property parent
- * @type DisplayObjectContainer
- * @readOnly
- */
- this.parent = null;
-
- /**
- * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage.
- *
- * @property stage
- * @type Stage
- * @readOnly
- */
- this.stage = null;
-
- /**
- * [read-only] The multiplied alpha of the displayObject
- *
- * @property worldAlpha
- * @type Number
- * @readOnly
- */
- this.worldAlpha = 1;
-
- /**
- * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property
- *
- * @property _interactive
- * @type Boolean
- * @readOnly
- * @private
- */
- this._interactive = false;
-
- /**
- * This is the cursor 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 = new PIXI.Matrix();
-
- /**
- * [NYI] Unknown
- *
- * @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;
-
- // cached sin rotation and cos rotation
- this._sr = 0;
- this._cr = 1;
-
- /**
- * The area the filter is applied to
- *
- * @property filterArea
- * @type Rectangle
- */
- this.filterArea = new PIXI.Rectangle(0,0,1,1);
-
- /**
- * The original, cached bounds of the object
- *
- * @property _bounds
- * @type Rectangle
- * @private
- */
- this._bounds = new PIXI.Rectangle(0, 0, 1, 1);
- /**
- * The most up-to-date bounds of the object
- *
- * @property _currentBounds
- * @type Rectangle
- * @private
- */
- this._currentBounds = null;
- /**
- * The original, cached mask of the object
- *
- * @property _currentBounds
- * @type Rectangle
- * @private
- */
- this._mask = null;
-
- /*
- * MOUSE Callbacks
- */
-
- /**
- * A callback that is used when the users clicks on the displayObject with their mouse
- * @method click
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user clicks the mouse down over the sprite
- * @method mousedown
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user releases the mouse that was over the displayObject
- * for this callback to be fired the mouse must have been pressed down over the displayObject
- * @method mouseup
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject
- * for this callback to be fired, The touch must have started over the displayObject
- * @method mouseupoutside
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the users mouse rolls over the displayObject
- * @method mouseover
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the users mouse leaves the displayObject
- * @method mouseout
- * @param interactionData {InteractionData}
- */
-
-
- /*
- * TOUCH Callbacks
- */
-
- /**
- * A callback that is used when the users taps on the sprite with their finger
- * basically a touch version of click
- * @method tap
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user touches over the displayObject
- * @method touchstart
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user releases a touch over the displayObject
- * @method touchend
- * @param interactionData {InteractionData}
- */
-
- /**
- * A callback that is used when the user releases the touch that was over the displayObject
- * for this callback to be fired, The touch must have started over the sprite
- * @method touchendoutside
- * @param interactionData {InteractionData}
- */
-};
-
-// constructor
-PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject;
-
-/**
- * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default
- * Instead of using this function you can now simply set the interactive property to true or false
- *
- * @method setInteractive
- * @param interactive {Boolean}
- * @deprecated Simply set the `interactive` property directly
- */
-PIXI.DisplayObject.prototype.setInteractive = function(interactive)
-{
- this.interactive = interactive;
-};
-
-/**
- * Indicates if the sprite will have touch and mouse interactivity. It is false by default
- *
- * @property interactive
- * @type Boolean
- * @default false
- */
-Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', {
- get: function() {
- return this._interactive;
- },
- set: function(value) {
- this._interactive = value;
-
- // TODO more to be done here..
- // need to sort out a re-crawl!
- if(this.stage)this.stage.dirty = true;
- }
-});
-
-/**
- * [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;
- }
-});
-
-/**
- * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it.
- * In PIXI a regular mask must be a PIXI.Graphics object. This allows for much faster masking in canvas as it utilises shape clipping.
- * To remove a mask, set this property to null.
- *
- * @property mask
- * @type Graphics
- */
-Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', {
- get: function() {
- return this._mask;
- },
- set: function(value) {
-
- if(this._mask)this._mask.isMask = false;
- this._mask = value;
- if(this._mask)this._mask.isMask = true;
- }
-});
-
-/**
- * Sets the filters for the displayObject.
- * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer.
- * To remove filters simply set this property to 'null'
- * @property filters
- * @type Array An array of filters
- */
-Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', {
- get: function() {
- return this._filters;
- },
- set: function(value) {
-
- if(value)
- {
- // 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
- *
- * @method updateTransform
- * @private
- */
-PIXI.DisplayObject.prototype.updateTransform = function()
-{
- // TODO OPTIMIZE THIS!! with dirty
- if(this.rotation !== this.rotationCache)
- {
-
- this.rotationCache = this.rotation;
- this._sr = Math.sin(this.rotation);
- this._cr = Math.cos(this.rotation);
- }
-
- // var localTransform = this.localTransform//.toArray();
- var parentTransform = this.parent.worldTransform;//.toArray();
- var worldTransform = this.worldTransform;//.toArray();
- var px = this.pivot.x;
- var py = this.pivot.y;
-
- var a00 = this._cr * this.scale.x,
- a01 = -this._sr * this.scale.y,
- a10 = this._sr * this.scale.x,
- a11 = this._cr * this.scale.y,
- a02 = this.position.x - a00 * px - py * a01,
- a12 = this.position.y - a11 * py - px * a10,
- b00 = parentTransform.a, b01 = parentTransform.b,
- b10 = parentTransform.c, b11 = parentTransform.d;
-
- worldTransform.a = b00 * a00 + b01 * a10;
- worldTransform.b = b00 * a01 + b01 * a11;
- worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx;
-
- worldTransform.c = b10 * a00 + b11 * a10;
- worldTransform.d = b10 * a01 + b11 * a11;
- worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty;
-
- this.worldAlpha = this.alpha * this.parent.worldAlpha;
-};
-
-/**
- * Retrieves the bounds of the displayObject as a rectangle object
- *
- * @method getBounds
- * @return {Rectangle} the rectangular bounding area
- */
-PIXI.DisplayObject.prototype.getBounds = function( matrix )
-{
- matrix = matrix;//just to get passed js hinting (and preserve inheritance)
- return PIXI.EmptyRectangle;
-};
-
-/**
- * Retrieves the local bounds of the displayObject as a rectangle object
- *
- * @method getLocalBounds
- * @return {Rectangle} the rectangular bounding area
- */
-PIXI.DisplayObject.prototype.getLocalBounds = function()
-{
- //var matrixCache = this.worldTransform;
-
- return this.getBounds(PIXI.identityMatrix);///PIXI.EmptyRectangle();
-};
-
-/**
- * Sets the object's stage reference, the stage this object is connected to
- *
- * @method setStageReference
- * @param stage {Stage} the stage that the object will have as its current stage reference
- */
-PIXI.DisplayObject.prototype.setStageReference = function(stage)
-{
- this.stage = stage;
- if(this._interactive)this.stage.dirty = true;
-};
-
-/**
-* Renders the object using the WebGL renderer
-*
-* @method _renderWebGL
-* @param renderSession {RenderSession}
-* @private
-*/
-PIXI.DisplayObject.prototype._renderWebGL = function(renderSession)
-{
- // OVERWRITE;
- // this line is just here to pass jshinting :)
- renderSession = renderSession;
-};
-
-/**
-* Renders the object using the Canvas renderer
-*
-* @method _renderCanvas
-* @param renderSession {RenderSession}
-* @private
-*/
-PIXI.DisplayObject.prototype._renderCanvas = function(renderSession)
-{
- // OVERWRITE;
- // this line is just here to pass jshinting :)
- renderSession = renderSession;
-};
-
-/**
- * The position of the displayObject on the x axis relative to the local coordinates of the parent.
- *
- * @property x
- * @type Number
- */
-Object.defineProperty(PIXI.DisplayObject.prototype, 'x', {
- get: function() {
- return this.position.x;
- },
- set: function(value) {
- this.position.x = value;
- }
-});
-
-/**
- * The position of the displayObject on the y axis relative to the local coordinates of the parent.
- *
- * @property y
- * @type Number
- */
-Object.defineProperty(PIXI.DisplayObject.prototype, 'y', {
- get: function() {
- return this.position.y;
- },
- set: function(value) {
- this.position.y = value;
- }
-});
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-
-/**
- * A DisplayObjectContainer represents a collection of display objects.
- * It is the base class of all display objects that act as a container for other objects.
- *
- * @class DisplayObjectContainer
- * @extends DisplayObject
- * @constructor
- */
-PIXI.DisplayObjectContainer = function()
-{
- PIXI.DisplayObject.call( this );
-
- /**
- * [read-only] The array 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;
-
-/**
- * The width of the displayObjectContainer, setting this will actually modify the scale to achieve the value set
- *
- * @property width
- * @type Number
- */
-
- /*
-Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'width', {
- get: function() {
- return this.scale.x * this.getLocalBounds().width;
- },
- set: function(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 achieve 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.
- *
- * @method addChild
- * @param child {DisplayObject} The DisplayObject to add to the container
- */
-PIXI.DisplayObjectContainer.prototype.addChild = function(child)
-{
- this.addChildAt(child, this.children.length);
-};
-
-/**
- * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown
- *
- * @method addChildAt
- * @param child {DisplayObject} The child to add
- * @param index {Number} The index to place the child in
- */
-PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index)
-{
- if(index >= 0 && index <= this.children.length)
- {
- if(child.parent)
- {
- child.parent.removeChild(child);
- }
-
- 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
- *
- * @method swapChildren
- * @param child {DisplayObject}
- * @param child2 {DisplayObject}
- * @private
- */
-PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2)
-{
- 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
- *
- * @method getChildAt
- * @param index {Number} The index to get the child from
- */
-PIXI.DisplayObjectContainer.prototype.getChildAt = function(index)
-{
- if(index >= 0 && index < this.children.length)
- {
- return this.children[index];
- }
- else
- {
- throw new Error('The supplied DisplayObjects must be a child of the caller ' + this);
- }
-};
-
-/**
- * Removes a child from the container.
- *
- * @method removeChild
- * @param child {DisplayObject} The DisplayObject to remove
- */
-PIXI.DisplayObjectContainer.prototype.removeChild = function(child)
-{
- var index = this.children.indexOf( child );
- if ( index !== -1 )
- {
- // 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);
- }
-};
-
-
-/**
-* Removes all the children
-*
-* @method removeAll
-* NOT tested yet
-*/
-/* PIXI.DisplayObjectContainer.prototype.removeAll = function()
-{
-
-
- for(var i = 0 , j = this.children.length; i < j; i++)
- {
- this.removeChild(this.children[i]);
- }
-
-};
-*/
-/*
- * Updates the container's childrens transform for rendering
- *
- * @method updateTransform
- * @private
- */
-PIXI.DisplayObjectContainer.prototype.updateTransform = function()
-{
- //this._currentBounds = null;
-
- 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;
- }
-
- if(!childVisible)
- return PIXI.EmptyRectangle;
-
- var bounds = this._bounds;
-
- bounds.x = minX;
- bounds.y = minY;
- bounds.width = maxX - minX;
- bounds.height = maxY - minY;
-
- // TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate
- //this._currentBounds = bounds;
-
- return bounds;
-};
-
-PIXI.DisplayObjectContainer.prototype.getLocalBounds = function()
-{
- var matrixCache = this.worldTransform;
-
- this.worldTransform = PIXI.identityMatrix;
-
- 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 reference so that if this function gets called again in the render cycle we do not have to recalculate
- this._currentBounds = bounds;
-
- return bounds;
-};
-
-/**
-* Renders the object using the WebGL renderer
-*
-* @method _renderWebGL
-* @param renderSession {RenderSession}
-* @private
-*/
-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 || 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} an array of {Texture} objects that make up the animation
- */
-PIXI.MovieClip = function(textures)
-{
- PIXI.Sprite.call(this, textures[0]);
-
- /**
- * The array of textures that make up the animation
- *
- * @property textures
- * @type Array
- */
- this.textures = textures;
-
- /**
- * The speed that the MovieClip will play at. Higher is faster, lower is slower
- *
- * @property animationSpeed
- * @type Number
- * @default 1
- */
- this.animationSpeed = 1;
-
- /**
- * Whether or not the movie clip repeats after playing.
- *
- * @property loop
- * @type Boolean
- * @default true
- */
- this.loop = true;
-
- /**
- * Function to call when a MovieClip finishes playing
- *
- * @property onComplete
- * @type Function
- */
- this.onComplete = null;
-
- /**
- * [read-only] The MovieClips current frame index (this may not have to be a whole number)
- *
- * @property currentFrame
- * @type Number
- * @default 0
- * @readOnly
- */
- this.currentFrame = 0;
-
- /**
- * [read-only] Indicates if the MovieClip is currently playing
- *
- * @property playing
- * @type Boolean
- * @readOnly
- */
- this.playing = false;
-};
-
-// constructor
-PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype );
-PIXI.MovieClip.prototype.constructor = PIXI.MovieClip;
-
-/**
-* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures
-* assigned to the MovieClip.
-*
-* @property totalFrames
-* @type Number
-* @default 0
-* @readOnly
-*/
-Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', {
- get: function() {
-
- return this.textures.length;
- }
-});
-
-
-/**
- * Stops the MovieClip
- *
- * @method stop
- */
-PIXI.MovieClip.prototype.stop = function()
-{
- this.playing = false;
-};
-
-/**
- * Plays the MovieClip
- *
- * @method play
- */
-PIXI.MovieClip.prototype.play = function()
-{
- this.playing = true;
-};
-
-/**
- * Stops the MovieClip and goes to a specific frame
- *
- * @method gotoAndStop
- * @param frameNumber {Number} frame index to stop at
- */
-PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber)
-{
- this.playing = false;
- this.currentFrame = frameNumber;
- var round = (this.currentFrame + 0.5) | 0;
- this.setTexture(this.textures[round % this.textures.length]);
-};
-
-/**
- * Goes to a specific frame and begins playing the MovieClip
- *
- * @method gotoAndPlay
- * @param frameNumber {Number} frame index to start at
- */
-PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber)
-{
- this.currentFrame = frameNumber;
- this.playing = true;
-};
-
-/*
- * Updates the object transform for rendering
- *
- * @method updateTransform
- * @private
- */
-PIXI.MovieClip.prototype.updateTransform = function()
-{
- PIXI.Sprite.prototype.updateTransform.call(this);
-
- if(!this.playing)return;
-
- this.currentFrame += this.animationSpeed;
-
- var round = (this.currentFrame + 0.5) | 0;
-
- if(this.loop || round < this.textures.length)
- {
- this.setTexture(this.textures[round % this.textures.length]);
- }
- else if(round >= this.textures.length)
- {
- this.gotoAndStop(this.textures.length - 1);
- if(this.onComplete)
- {
- this.onComplete();
- }
- }
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-
-PIXI.FilterBlock = function()
-{
- this.visible = true;
- this.renderable = true;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * A Text Object will create a line(s) of text. To split a line you can use '\n'
- * or add a wordWrap property set to true and and wordWrapWidth property with a value
- * in the style object
- *
- * @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 20px Arial' The style and size of the font
- * @param [style.fill='black'] {String|Number} A canvas fillstyle that will be used on the text e.g 'red', '#00FF00'
- * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
- * @param [style.stroke] {String|Number} A canvas fillstyle that will be used on the text stroke e.g '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, it needs wordWrap to be set to true
- */
-PIXI.Text = function(text, style)
-{
- /**
- * The canvas element that everything is drawn to
- *
- * @property canvas
- * @type HTMLCanvasElement
- */
- this.canvas = document.createElement('canvas');
-
- /**
- * The canvas 2d context that everything is drawn with
- * @property context
- * @type HTMLCanvasElement 2d Context
- */
- this.context = this.canvas.getContext('2d');
-
- PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas));
-
- this.setText(text);
- this.setStyle(style);
-
- this.updateText();
- this.dirty = false;
-};
-
-// constructor
-PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype);
-PIXI.Text.prototype.constructor = PIXI.Text;
-
-/**
- * Set the style of the text
- *
- * @method setStyle
- * @param [style] {Object} The style parameters
- * @param [style.font='bold 20pt Arial'] {String} The style and size of the font
- * @param [style.fill='black'] {Object} A canvas fillstyle that will be used on the text eg 'red', '#00FF00'
- * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
- * @param [style.stroke='black'] {String} A canvas fillstyle that will be used on the text stroke eg 'blue', '#FCFF00'
- * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
- * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
- * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
- */
-PIXI.Text.prototype.setStyle = function(style)
-{
- style = style || {};
- style.font = style.font || 'bold 20pt Arial';
- style.fill = style.fill || 'black';
- style.align = style.align || 'left';
- style.stroke = style.stroke || 'black'; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
- style.strokeThickness = style.strokeThickness || 0;
- style.wordWrap = style.wordWrap || false;
- style.wordWrapWidth = style.wordWrapWidth || 100;
- this.style = style;
- this.dirty = true;
-};
-
-/**
- * Set the copy for the text object. To split a line you can use '\n'
- *
- * @method setText
- * @param {String} text The copy that you would like the text to display
- */
-PIXI.Text.prototype.setText = function(text)
-{
- this.text = text.toString() || ' ';
- this.dirty = true;
-
-};
-
-/**
- * Renders text and updates it when needed
- *
- * @method updateText
- * @private
- */
-PIXI.Text.prototype.updateText = function()
-{
- this.context.font = this.style.font;
-
- var outputText = this.text;
-
- // word wrap
- // preserve original text
- if(this.style.wordWrap)outputText = this.wordWrap(this.text);
-
- //split text into lines
- var lines = outputText.split(/(?:\r\n|\r|\n)/);
-
- //calculate text width
- var lineWidths = [];
- var maxLineWidth = 0;
- for (var i = 0; i < lines.length; i++)
- {
- var lineWidth = this.context.measureText(lines[i]).width;
- lineWidths[i] = lineWidth;
- maxLineWidth = Math.max(maxLineWidth, lineWidth);
- }
- this.canvas.width = maxLineWidth + this.style.strokeThickness;
-
- //calculate text height
- var lineHeight = this.determineFontHeight('font: ' + this.style.font + ';') + this.style.strokeThickness;
- this.canvas.height = lineHeight * lines.length;
-
- 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);
- }
- }
-
- this.updateTexture();
-};
-
-/**
- * Updates texture size based on canvas size
- *
- * @method updateTexture
- * @private
- */
-PIXI.Text.prototype.updateTexture = function()
-{
- this.texture.baseTexture.width = this.canvas.width;
- this.texture.baseTexture.height = this.canvas.height;
- this.texture.frame.width = this.canvas.width;
- this.texture.frame.height = this.canvas.height;
-
- this._width = this.canvas.width;
- this._height = this.canvas.height;
-
- this.requiresUpdate = true;
-};
-
-/**
-* Renders the object using the WebGL renderer
-*
-* @method _renderWebGL
-* @param renderSession {RenderSession}
-* @private
-*/
-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);
-};
-
-/**
- * Updates the transform of this object
- *
- * @method updateTransform
- * @private
- */
-PIXI.Text.prototype.updateTransform = function()
-{
- if(this.dirty)
- {
- this.updateText();
- this.dirty = false;
- }
-
- PIXI.Sprite.prototype.updateTransform.call(this);
-};
-
-/*
- * http://stackoverflow.com/users/34441/ellisbben
- * great solution to the problem!
- * returns the height of the given font
- *
- * @method determineFontHeight
- * @param fontStyle {Object}
- * @private
- */
-PIXI.Text.prototype.determineFontHeight = function(fontStyle)
-{
- // build a little reference dictionary so if the font style has been used return a
- // cached version...
- var result = PIXI.Text.heightCache[fontStyle];
-
- if(!result)
- {
- var body = document.getElementsByTagName('body')[0];
- var dummy = document.createElement('div');
- var dummyText = document.createTextNode('M');
- dummy.appendChild(dummyText);
- dummy.setAttribute('style', fontStyle + ';position:absolute;top:0;left:0');
- body.appendChild(dummy);
-
- result = dummy.offsetHeight;
- PIXI.Text.heightCache[fontStyle] = result;
-
- body.removeChild(dummy);
- }
-
- return result;
-};
-
-/**
- * Applies newlines to a string to have it optimally fit into the horizontal
- * bounds set by the Text object's wordWrapWidth property.
- *
- * @method wordWrap
- * @param text {String}
- * @private
- */
-PIXI.Text.prototype.wordWrap = function(text)
-{
- // Greedy wrapping algorithm that will wrap words as the line grows longer
- // than its horizontal bounds.
- var result = '';
- var lines = text.split('\n');
- for (var i = 0; i < lines.length; i++)
- {
- var spaceLeft = this.style.wordWrapWidth;
- var words = lines[i].split(' ');
- for (var j = 0; j < words.length; j++)
- {
- var wordWidth = this.context.measureText(words[j]).width;
- var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width;
- if(wordWidthWithSpace > spaceLeft)
- {
- // Skip printing the newline if it's the first word of the line that is
- // greater than the word wrap width.
- if(j > 0)
- {
- result += '\n';
- }
- result += words[j] + ' ';
- spaceLeft = this.style.wordWrapWidth - wordWidth;
- }
- else
- {
- spaceLeft -= wordWidthWithSpace;
- result += words[j] + ' ';
- }
- }
-
- if (i < lines.length-1)
- {
- result += '\n';
- }
- }
- return result;
-};
-
-/**
- * Destroys this text object
- *
- * @method destroy
- * @param destroyTexture {Boolean}
- */
-PIXI.Text.prototype.destroy = function(destroyTexture)
-{
- if(destroyTexture)
- {
- this.texture.destroy();
- }
-
-};
-
-PIXI.Text.heightCache = {};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * A Text Object will create a line(s) of text using bitmap font. To split a line you can use '\n', '\r' or '\r\n'
- * You can generate the fnt files using
- * http://www.angelcode.com/products/bmfont/ for windows or
- * http://www.bmglyph.com/ for mac.
- *
- * @class BitmapText
- * @extends DisplayObjectContainer
- * @constructor
- * @param text {String} The copy that you would like the text to display
- * @param style {Object} The style parameters
- * @param style.font {String} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously)
- * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
- */
-PIXI.BitmapText = function(text, style)
-{
- PIXI.DisplayObjectContainer.call(this);
-
- this._pool = [];
-
- this.setText(text);
- this.setStyle(style);
- this.updateText();
- this.dirty = false;
-};
-
-// constructor
-PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
-PIXI.BitmapText.prototype.constructor = PIXI.BitmapText;
-
-/**
- * Set the copy for the text object
- *
- * @method setText
- * @param text {String} The copy that you would like the text to display
- */
-PIXI.BitmapText.prototype.setText = function(text)
-{
- this.text = text || ' ';
- this.dirty = true;
-};
-
-/**
- * Set the style of the text
- * style.font {String} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously)
- * [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
- *
- * @method setStyle
- * @param style {Object} The style parameters, contained as properties of an object
- */
-PIXI.BitmapText.prototype.setStyle = function(style)
-{
- style = style || {};
- style.align = style.align || 'left';
- this.style = style;
-
- var font = style.font.split(' ');
- this.fontName = font[font.length - 1];
- this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size;
-
- this.dirty = true;
- this.tint = style.tint;
-};
-
-/**
- * Renders text and updates it when needed
- *
- * @method updateText
- * @private
- */
-PIXI.BitmapText.prototype.updateText = function()
-{
- var data = PIXI.BitmapText.fonts[this.fontName];
- var pos = new PIXI.Point();
- var prevCharCode = null;
- var chars = [];
- var maxLineWidth = 0;
- var lineWidths = [];
- var line = 0;
- var scale = this.fontSize / data.size;
-
-
- for(var i = 0; i < this.text.length; i++)
- {
- var charCode = this.text.charCodeAt(i);
- if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i)))
- {
- lineWidths.push(pos.x);
- maxLineWidth = Math.max(maxLineWidth, pos.x);
- line++;
-
- pos.x = 0;
- pos.y += data.lineHeight;
- prevCharCode = null;
- continue;
- }
-
- var charData = data.chars[charCode];
- if(!charData) continue;
-
- if(prevCharCode && charData[prevCharCode])
- {
- pos.x += charData.kerning[prevCharCode];
- }
- chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)});
- pos.x += charData.xAdvance;
-
- prevCharCode = charCode;
- }
-
- lineWidths.push(pos.x);
- maxLineWidth = Math.max(maxLineWidth, pos.x);
-
- var lineAlignOffsets = [];
- for(i = 0; i <= line; i++)
- {
- var alignOffset = 0;
- if(this.style.align === 'right')
- {
- alignOffset = maxLineWidth - lineWidths[i];
- }
- else if(this.style.align === 'center')
- {
- alignOffset = (maxLineWidth - lineWidths[i]) / 2;
- }
- lineAlignOffsets.push(alignOffset);
- }
-
- var lenChildren = this.children.length;
- var lenChars = chars.length;
- var tint = this.tint || 0xFFFFFF;
- for(i = 0; i < lenChars; i++)
- {
- var c = i < lenChildren ? this.children[i] : this._pool.pop(); // get old child if have. if not - take from pool.
-
- if (c) c.setTexture(chars[i].texture); // check if got one before.
- else c = new PIXI.Sprite(chars[i].texture); // if no create new one.
-
- 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;
- c.tint = tint;
- if (!c.parent) this.addChild(c);
- }
-
- // remove unnecessary children.
- // and put their into the pool.
- while(this.children.length > lenChars)
- {
- var child = this.getChildAt(this.children.length - 1);
- this._pool.push(child);
- this.removeChild(child);
- }
-
-
- /**
- * [read-only] The width of the overall text, different from fontSize,
- * which is defined in the style object
- *
- * @property textWidth
- * @type Number
- */
- this.textWidth = maxLineWidth * scale;
-
- /**
- * [read-only] The height of the overall text, different from fontSize,
- * which is defined in the style object
- *
- * @property textHeight
- * @type Number
- */
- this.textHeight = (pos.y + data.lineHeight) * scale;
-};
-
-/**
- * Updates the transform of this object
- *
- * @method updateTransform
- * @private
- */
-PIXI.BitmapText.prototype.updateTransform = function()
-{
- if(this.dirty)
- {
- this.updateText();
- this.dirty = false;
- }
-
- PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
-};
-
-PIXI.BitmapText.fonts = {};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * Holds all information related to an Interaction event
- *
- * @class InteractionData
- * @constructor
- */
-PIXI.InteractionData = function()
-{
- /**
- * This point stores the global coords of where the touch/mouse event happened
- *
- * @property global
- * @type Point
- */
- this.global = new PIXI.Point();
-
- // this is here for legacy... but will remove
- this.local = new PIXI.Point();
-
- /**
- * The target Sprite that was interacted with
- *
- * @property target
- * @type Sprite
- */
- this.target = 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 coordinates of the specified displayObject for this InteractionData
- *
- * @method getLocalPosition
- * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off
- * @return {Point} A point containing the coordinates of the InteractionData position relative to the DisplayObject
- */
-PIXI.InteractionData.prototype.getLocalPosition = function(displayObject)
-{
- var worldTransform = displayObject.worldTransform;
- var global = this.global;
-
- // do a cheeky transform to get the mouse coords;
- var a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx,
- a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty,
- id = 1 / (a00 * a11 + a01 * -a10);
- // set the mouse coords...
- return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id,
- a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id);
-};
-
-// constructor
-PIXI.InteractionData.prototype.constructor = PIXI.InteractionData;
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
- /**
- * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive
- * if its interactive parameter is set to true
- * This manager also supports multitouch.
- *
- * @class InteractionManager
- * @constructor
- * @param stage {Stage} The stage to handle interactions
- */
-PIXI.InteractionManager = function(stage)
-{
- /**
- * a reference to the stage
- *
- * @property stage
- * @type Stage
- */
- this.stage = stage;
-
- /**
- * the mouse data
- *
- * @property mouse
- * @type InteractionData
- */
- this.mouse = new PIXI.InteractionData();
-
- /**
- * an object that stores current touches (InteractionData) by id reference
- *
- * @property touchs
- * @type Object
- */
- this.touchs = {};
-
- // helpers
- this.tempPoint = new PIXI.Point();
-
- /**
- *
- * @property mouseoverEnabled
- * @type Boolean
- * @default
- */
- this.mouseoverEnabled = true;
-
- /**
- * tiny little interactiveData pool !
- *
- * @property pool
- * @type Array
- */
- this.pool = [];
-
- /**
- * An array containing all the iterative items from the our interactive tree
- * @property interactiveItems
- * @type Array
- * @private
- *
- */
- this.interactiveItems = [];
-
- /**
- * Our canvas
- * @property interactionDOMElement
- * @type HTMLCanvasElement
- * @private
- */
- this.interactionDOMElement = null;
-
- //this will make it so that you dont have to call bind all the time
- this.onMouseMove = this.onMouseMove.bind( this );
- this.onMouseDown = this.onMouseDown.bind(this);
- this.onMouseOut = this.onMouseOut.bind(this);
- this.onMouseUp = this.onMouseUp.bind(this);
-
- this.onTouchStart = this.onTouchStart.bind(this);
- this.onTouchEnd = this.onTouchEnd.bind(this);
- this.onTouchMove = this.onTouchMove.bind(this);
-
- this.last = 0;
-
- /**
- * The css style of the cursor that is being used
- * @property currentCursorStyle
- * @type String
- *
- */
- this.currentCursorStyle = 'inherit';
-
- /**
- * Is set to true when the mouse is moved out of the canvas
- * @property mouseOut
- * @type Boolean
- *
- */
- this.mouseOut = false;
-};
-
-// constructor
-PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager;
-
-/**
- * Collects an interactive sprite recursively to have their interactions managed
- *
- * @method collectInteractiveSprite
- * @param displayObject {DisplayObject} the displayObject to collect
- * @param iParent {DisplayObject} the display object's parent
- * @private
- */
-PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent)
-{
- var children = displayObject.children;
- var length = children.length;
-
- // make an interaction tree... {item.__interactiveParent}
- for (var i = length-1; i >= 0; i--)
- {
- var child = children[i];
-
- // push all interactive bits
- if(child.interactive)
- {
- iParent.interactiveChildren = true;
- //child.__iParent = iParent;
- this.interactiveItems.push(child);
-
- if(child.children.length > 0)
- {
- this.collectInteractiveSprite(child, child);
- }
- }
- else
- {
- child.__iParent = null;
-
- if(child.children.length > 0)
- {
- this.collectInteractiveSprite(child, iParent);
- }
- }
-
- }
-};
-
-/**
- * Sets the target for event delegation
- *
- * @method setTarget
- * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to
- * @private
- */
-PIXI.InteractionManager.prototype.setTarget = function(target)
-{
- this.target = target;
-
- //check if the dom element has been set. If it has don't do anything
- if( this.interactionDOMElement === null ) {
-
- this.setTargetDomElement( target.view );
- }
-
-
-};
-
-
-/**
- * Sets the DOM element which will receive mouse/touch events. This is useful for when you have other DOM
- * elements on top of the renderers Canvas element. With this you'll be 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)
-{
-
- this.removeEvents();
-
-
- 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);
-
- document.body.addEventListener('mouseup', this.onMouseUp, true);
-};
-
-
-PIXI.InteractionManager.prototype.removeEvents = function()
-{
- if(!this.interactionDOMElement)return;
-
- 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);
-
- this.interactionDOMElement = null;
-
- document.body.removeEventListener('mouseup', this.onMouseUp, true);
-};
-
-/**
- * updates the state of interactive objects
- *
- * @method update
- * @private
- */
-PIXI.InteractionManager.prototype.update = function()
-{
- if(!this.target)return;
-
- // frequency of 30fps??
- var now = Date.now();
- var diff = now - this.last;
- diff = (diff * PIXI.INTERACTION_FREQUENCY ) / 1000;
- if(diff < 1)return;
- this.last = now;
-
- var i = 0;
-
- // ok.. so mouse events??
- // yes for now :)
- // OPTIMISE - 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;
- var cursor = 'inherit';
- var over = false;
-
- for (i = 0; i < length; i++)
- {
- var item = this.interactiveItems[i];
-
- // 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..
- // looks like there was a hit!
- if(item.__hit && !over)
- {
- if(item.buttonMode) cursor = item.defaultCursor;
-
- if(!item.interactiveChildren)over = true;
-
- 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.currentCursorStyle !== cursor )
- {
- this.currentCursorStyle = cursor;
- this.interactionDOMElement.style.cursor = cursor;
- }
-};
-
-/**
- * Is called when the mouse moves across the renderer element
- *
- * @method onMouseMove
- * @param event {Event} The DOM event of the mouse moving
- * @private
- */
-PIXI.InteractionManager.prototype.onMouseMove = function(event)
-{
- this.mouse.originalEvent = event || window.event; //IE uses window.event
- // TODO optimize by not check EVERY TIME! maybe half as often? //
- var rect = this.interactionDOMElement.getBoundingClientRect();
-
- this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width);
- this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height);
-
- var length = this.interactiveItems.length;
-
- for (var i = 0; i < length; i++)
- {
- var item = this.interactiveItems[i];
-
- if(item.mousemove)
- {
- //call the function!
- item.mousemove(this.mouse);
- }
- }
-};
-
-/**
- * Is called when the mouse button is pressed down on the renderer element
- *
- * @method onMouseDown
- * @param event {Event} The DOM event of a mouse button being pressed down
- * @private
- */
-PIXI.InteractionManager.prototype.onMouseDown = function(event)
-{
- this.mouse.originalEvent = event || window.event; //IE uses window.event
-
- if(PIXI.AUTO_PREVENT_DEFAULT)this.mouse.originalEvent.preventDefault();
-
- // loop through interaction 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;
- }
- }
- }
-};
-
-/**
- * Is called when the mouse button is moved out of the renderer element
- *
- * @method onMouseOut
- * @param event {Event} The DOM event of a mouse button being moved out
- * @private
- */
-PIXI.InteractionManager.prototype.onMouseOut = function()
-{
- var length = this.interactiveItems.length;
-
- this.interactionDOMElement.style.cursor = '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;
- }
- }
-
- this.mouseOut = true;
-
- // move the mouse to an impossible position
- this.mouse.global.x = -10000;
- this.mouse.global.y = -10000;
-};
-
-/**
- * Is called when the mouse button is released on the renderer element
- *
- * @method onMouseUp
- * @param event {Event} The DOM event of a mouse button being released
- * @private
- */
-PIXI.InteractionManager.prototype.onMouseUp = function(event)
-{
-
- this.mouse.originalEvent = event || window.event; //IE uses window.event
-
- var length = this.interactiveItems.length;
- var up = false;
-
- for (var i = 0; i < length; i++)
- {
- var item = this.interactiveItems[i];
-
- 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 coordinates hit a sprite
- *
- * @method hitTest
- * @param item {DisplayObject} The displayObject to test for a hit
- * @param interactionData {InteractionData} The interactionData object to update in the case there is a hit
- * @private
- */
-PIXI.InteractionManager.prototype.hitTest = function(item, interactionData)
-{
- var global = interactionData.global;
-
- if( !item.worldVisible )return false;
-
- // temp fix for if the element is in a non visible
-
- var isSprite = (item instanceof PIXI.Sprite),
- worldTransform = item.worldTransform,
- a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx,
- a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty,
- id = 1 / (a00 * a11 + a01 * -a10),
- x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id,
- y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id;
-
- interactionData.target = item;
-
- //a sprite or display object with a hit area defined
- if(item.hitArea && item.hitArea.contains) {
- if(item.hitArea.contains(x, y)) {
- //if(isSprite)
- interactionData.target = item;
-
- return true;
- }
-
- return false;
- }
- // a sprite with no hitarea defined
- else if(isSprite)
- {
- var width = item.texture.frame.width,
- height = item.texture.frame.height,
- x1 = -width * item.anchor.x,
- y1;
-
- if(x > x1 && x < x1 + width)
- {
- y1 = -height * item.anchor.y;
-
- if(y > y1 && y < y1 + height)
- {
- // set the target property if a hit is true!
- interactionData.target = item;
- return true;
- }
- }
- }
-
- var length = item.children.length;
-
- for (var i = 0; i < length; i++)
- {
- var tempItem = item.children[i];
- var hit = this.hitTest(tempItem, interactionData);
- if(hit)
- {
- // hmm.. TODO SET CORRECT TARGET?
- interactionData.target = item;
- return true;
- }
- }
-
- return false;
-};
-
-/**
- * Is called when a touch is moved across the renderer element
- *
- * @method onTouchMove
- * @param event {Event} The DOM event of a touch moving across the renderer view
- * @private
- */
-PIXI.InteractionManager.prototype.onTouchMove = function(event)
-{
- 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
- *
- * @method onTouchStart
- * @param event {Event} The DOM event of a touch starting on the renderer view
- * @private
- */
-PIXI.InteractionManager.prototype.onTouchStart = function(event)
-{
- var rect = this.interactionDOMElement.getBoundingClientRect();
-
- if(PIXI.AUTO_PREVENT_DEFAULT)event.preventDefault();
-
- 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
- *
- * @method onTouchEnd
- * @param event {Event} The DOM event of a touch ending on the renderer view
- * @private
- */
-PIXI.InteractionManager.prototype.onTouchEnd = function(event)
-{
- //this.mouse.originalEvent = event || window.event; //IE uses window.event
- var rect = this.interactionDOMElement.getBoundingClientRect();
- var changedTouches = event.changedTouches;
-
- for (var i=0; i < changedTouches.length; i++)
- {
- var touchEvent = changedTouches[i];
- var touchData = this.touchs[touchEvent.identifier];
- var up = false;
- touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width);
- touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height);
- 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;
- }
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * A Stage represents the root of the display tree. Everything connected to the stage is rendered
- *
- * @class Stage
- * @extends DisplayObjectContainer
- * @constructor
- * @param backgroundColor {Number} the background color of the stage, you have to pass this in is in hex format
- * like: 0xFFFFFF for white
- *
- * Creating a stage is a mandatory process when you use Pixi, which is as simple as this :
- * var stage = new PIXI.Stage(0xFFFFFF);
- * where the parameter given is the background colour of the stage, in hex
- * you will use this stage instance to add your sprites to it and therefore to the renderer
- * Here is how to add a sprite to the stage :
- * stage.addChild(sprite);
- */
-PIXI.Stage = function(backgroundColor)
-{
- PIXI.DisplayObjectContainer.call( this );
-
- /**
- * [read-only] Current transform of the object based on world (parent) factors
- *
- * @property worldTransform
- * @type Mat3
- * @readOnly
- * @private
- */
- this.worldTransform = new PIXI.Matrix();
-
- /**
- * Whether or not the stage is interactive
- *
- * @property interactive
- * @type Boolean
- */
- this.interactive = true;
-
- /**
- * The interaction manage for this stage, manages all interactive activity on the stage
- *
- * @property interactive
- * @type InteractionManager
- */
- this.interactionManager = new PIXI.InteractionManager(this);
-
- /**
- * Whether the stage is dirty and needs to have interactions updated
- *
- * @property dirty
- * @type Boolean
- * @private
- */
- this.dirty = true;
-
- //the stage is its own stage
- this.stage = this;
-
- //optimize hit detection a bit
- this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000);
-
- 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 on top of the Canvas element.
- *
- * @method setInteractionDelegate
- * @param domElement {DOMElement} This new domElement which will receive mouse/touch events
- */
-PIXI.Stage.prototype.setInteractionDelegate = function(domElement)
-{
- this.interactionManager.setTargetDomElement( domElement );
-};
-
-/*
- * Updates the object transform for rendering
- *
- * @method updateTransform
- * @private
- */
-PIXI.Stage.prototype.updateTransform = function()
-{
- this.worldAlpha = 1;
-
- for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255];
-};
-
-/**
- * Converts a color as an [R, G, B] array to a hex number
- *
- * @method rgb2hex
- * @param rgb {Array}
- */
-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) {
- if (proto) F.prototype = proto;
- if (!(this instanceof F)) return new F();
- })(target.prototype);
-
- return bound;
- };
- })();
-}
-
-/**
- * A wrapper for ajax requests to be handled cross browser
- *
- * @class AjaxRequest
- * @constructor
- */
-PIXI.AjaxRequest = function()
-{
- var activexmodes = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']; //activeX versions to check for in IE
-
- if (window.ActiveXObject)
- { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
- for (var i=0; i 0 && (number & (number - 1)) === 0) // see: http://goo.gl/D9kPj
- return number;
- else
- {
- var result = 1;
- while (result < number) result <<= 1;
- return result;
- }
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * https://github.com/mrdoob/eventtarget.js/
- * THankS mr DOob!
- */
-
-/**
- * Adds event emitter functionality to a class
- *
- * @class EventTarget
- * @example
- * function MyEmitter() {
- * PIXI.EventTarget.call(this); //mixes in event target stuff
- * }
- *
- * var em = new MyEmitter();
- * em.emit({ type: 'eventName', data: 'some data' });
- */
-PIXI.EventTarget = function () {
-
- /**
- * Holds all the listeners
- *
- * @property listeneners
- * @type Object
- */
- var listeners = {};
-
- /**
- * Adds a listener for a specific event
- *
- * @method addEventListener
- * @param type {string} A string representing the event type to listen for.
- * @param listener {function} The callback function that will be fired when the event occurs
- */
- this.addEventListener = this.on = function ( type, listener ) {
-
-
- if ( listeners[ type ] === undefined ) {
-
- listeners[ type ] = [];
-
- }
-
- if ( listeners[ type ].indexOf( listener ) === - 1 ) {
-
- listeners[ type ].push( listener );
- }
-
- };
-
- /**
- * Fires the event, ie pretends that the event has happened
- *
- * @method dispatchEvent
- * @param event {Event} the event object
- */
- 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 );
-
- }
-
- };
-
- /**
- * Removes the specified listener that was assigned to the specified event type
- *
- * @method removeEventListener
- * @param type {string} A string representing the event type which will have its listener removed
- * @param listener {function} The callback function that was be fired when the event occured
- */
- this.removeEventListener = this.off = function ( type, listener ) {
-
- var index = listeners[ type ].indexOf( listener );
-
- if ( index !== - 1 ) {
-
- listeners[ type ].splice( index, 1 );
-
- }
-
- };
-
- /**
- * Removes all the listeners that were active for the specified event type
- *
- * @method removeAllEventListeners
- * @param type {string} A string representing the event type which will have all its listeners removed
- */
- this.removeAllEventListeners = function( type ) {
- var a = listeners[type];
- if (a)
- a.length = 0;
- };
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * This helper function will automatically detect which renderer you should be using.
- * WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
- * the browser then this function will return a canvas renderer
- * @class autoDetectRenderer
- * @static
- * @param width=800 {Number} the width of the renderers view
- * @param height=600 {Number} the height of the renderers view
- * @param [view] {Canvas} the canvas to use as a view, optional
- * @param [transparent=false] {Boolean} the transparency of the render view, default false
- * @param [antialias=false] {Boolean} sets antialias (only applicable in webGL chrome at the moment)
- *
- */
-PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias)
-{
- if(!width)width = 800;
- if(!height)height = 600;
-
- // BORROWED from Mr Doob (mrdoob.com)
- var webgl = ( function () { try {
- var canvas = document.createElement( 'canvas' );
- return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) );
- } catch( e ) {
- return false;
- }
- } )();
-
-
- if( webgl )
- {
- return new PIXI.WebGLRenderer(width, height, view, transparent, antialias);
- }
-
- return new PIXI.CanvasRenderer(width, height, view, transparent);
-};
-
-/*
- PolyK library
- url: http://polyk.ivank.net
- Released under MIT licence.
-
- Copyright (c) 2012 Ivan Kuckir
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
- This is an amazing lib!
-
- slightly modified by Mat Groves (matgroves.com);
-*/
-
-/**
- * Based on the Polyk library http://polyk.ivank.net released under MIT licence.
- * This is an amazing lib!
- * slightly modified by Mat Groves (matgroves.com);
- * @class PolyK
- *
- */
-PIXI.PolyK = {};
-
-/**
- * Triangulates shapes for webGL graphic fills
- *
- * @method Triangulate
- *
- */
-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 < 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 whether a point is within a triangle
- *
- * @method _PointInTriangle
- * @param px {Number} x coordinate of the point to test
- * @param py {Number} y coordinate of the point to test
- * @param ax {Number} x coordinate of the a point of the triangle
- * @param ay {Number} y coordinate of the a point of the triangle
- * @param bx {Number} x coordinate of the b point of the triangle
- * @param by {Number} y coordinate of the b point of the triangle
- * @param cx {Number} x coordinate of the c point of the triangle
- * @param cy {Number} y coordinate of the c point of the triangle
- * @private
- */
-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;
-
- // Check if point is in triangle
- return (u >= 0) && (v >= 0) && (u + v < 1);
-};
-
-/**
- * Checks whether a shape is convex
- *
- * @method _convex
- *
- * @private
- */
-PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign)
-{
- return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) === sign;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-// TODO Alvin and Mat
-// Should we eventually create a Utils class ?
-// Or just move this file to the pixi.js file ?
-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 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 PixiShader
-* @constructor
-*/
-PIXI.PixiShader = function(gl)
-{
- /**
- * @property gl
- * @type WebGLContext
- */
- 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.attributes = [];
-
- this.init();
-};
-
-/**
-* Initialises the shader
-* @method 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 something 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;
- }
-
- this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute];
-
- // 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 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 has loaded)
-*
-* @method 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, !!data.flipY);
-
- 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 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);
- }
- }
- }
-
-};
-
-/**
-* Destroys the shader
-* @method destroy
-*
-*/
-PIXI.PixiShader.prototype.destroy = function()
-{
- this.gl.deleteProgram( this.program );
- this.uniforms = null;
- this.gl = null;
-
- this.attributes = null;
-};
-
-/**
-*
-* @property defaultVertexSrc
-* @type String
-*/
-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);',
- '}'
-];
-
-
-
-
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- * @author Richard Davey http://www.photonstorm.com @photonstorm
- */
-
-/**
-* @class PixiFastShader
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-*/
-PIXI.PixiFastShader = function(gl)
-{
-
- /**
- * @property gl
- * @type WebGLContext
- */
- 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 float vColor;',
- 'uniform sampler2D uSampler;',
- 'void main(void) {',
- ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
- '}'
- ];
-
- /**
- * @property {array} vertexSrc - The vertex shader
- */
- this.vertexSrc = [
- 'attribute vec2 aVertexPosition;',
- 'attribute vec2 aPositionCoord;',
- 'attribute vec2 aScale;',
- 'attribute float aRotation;',
- 'attribute vec2 aTextureCoord;',
- 'attribute float aColor;',
-
- 'uniform vec2 projectionVector;',
- 'uniform vec2 offsetVector;',
- 'uniform mat3 uMatrix;',
-
- 'varying vec2 vTextureCoord;',
- 'varying float vColor;',
-
- 'const vec2 center = vec2(-1.0, 1.0);',
-
- 'void main(void) {',
- ' vec2 v;',
- ' vec2 sv = aVertexPosition * aScale;',
- ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);',
- ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);',
- ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;',
- ' gl_Position = vec4( ( v / 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 = aColor;',
- '}'
- ];
-
-
- /**
- * @property {number} textureCount - A local texture counter for multi-texture shaders.
- */
- this.textureCount = 0;
-
-
- this.init();
-};
-
-/**
-* Initialises the shader
-* @method init
-*
-*/
-PIXI.PixiFastShader.prototype.init = function()
-{
-
- var gl = this.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.dimensions = gl.getUniformLocation(program, 'dimensions');
- this.uMatrix = gl.getUniformLocation(program, 'uMatrix');
-
- // get and store the attributes
- this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
- this.aPositionCoord = gl.getAttribLocation(program, 'aPositionCoord');
-
- this.aScale = gl.getAttribLocation(program, 'aScale');
- this.aRotation = gl.getAttribLocation(program, 'aRotation');
-
- 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;
- }
-
- this.attributes = [this.aVertexPosition, this.aPositionCoord, this.aScale, this.aRotation, this.aTextureCoord, this.colorAttribute];
-
- // End worst hack eva //
-
-
- this.program = program;
-};
-
-/**
-* Destroys the shader
-* @method destroy
-*
-*/
-PIXI.PixiFastShader.prototype.destroy = function()
-{
- this.gl.deleteProgram( this.program );
- this.uniforms = null;
- this.gl = null;
-
- this.attributes = null;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-
-PIXI.StripShader = function()
-{
- /**
- * @property {any} program - The WebGL program.
- */
- this.program = null;
-
- /**
- * @property {array} fragmentSrc - The fragment shader.
- */
- 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;',
- '}'
- ];
-
- /**
- * @property {array} fragmentSrc - The fragment shader.
- */
- 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;',
- '}'
- ];
-};
-
-/**
-* Initialises the shader
-* @method init
-*
-*/
-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
- */
-
-/**
-* @class PrimitiveShader
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-*/
-PIXI.PrimitiveShader = function(gl)
-{
- /**
- * @property gl
- * @type WebGLContext
- */
- this.gl = gl;
-
- /**
- * @property {any} program - The WebGL program.
- */
- this.program = null;
-
- /**
- * @property fragmentSrc
- * @type Array
- */
- this.fragmentSrc = [
- 'precision mediump float;',
- 'varying vec4 vColor;',
-
- 'void main(void) {',
- ' gl_FragColor = vColor;',
- '}'
- ];
-
- /**
- * @property vertexSrc
- * @type Array
- */
- 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();
-};
-
-/**
-* Initialises the shader
-* @method init
-*
-*/
-PIXI.PrimitiveShader.prototype.init = function()
-{
-
- var gl = this.gl;
-
- var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
- gl.useProgram(program);
-
- // 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');
-
-
- // get and store the attributes
- this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
- this.colorAttribute = gl.getAttribLocation(program, 'aColor');
-
- this.attributes = [this.aVertexPosition, this.colorAttribute];
-
- this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
- this.alpha = gl.getUniformLocation(program, 'alpha');
-
- this.program = program;
-};
-
-/**
-* Destroys the shader
-* @method destroy
-*
-*/
-PIXI.PrimitiveShader.prototype.destroy = function()
-{
- this.gl.deleteProgram( this.program );
- this.uniforms = null;
- this.gl = null;
-
- this.attribute = null;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * A set of functions used by the webGL renderer to draw the primitive graphics data
- *
- * @class WebGLGraphics
- * @private
- * @static
- */
-PIXI.WebGLGraphics = function()
-{
-
-};
-
-/**
- * Renders the graphics object
- *
- * @static
- * @private
- * @method renderGraphics
- * @param graphics {Graphics}
- * @param renderSession {Object}
- */
-PIXI.WebGLGraphics.renderGraphics = function(graphics, renderSession)//projection, offset)
-{
- var gl = renderSession.gl;
- var projection = renderSession.projection,
- offset = renderSession.offset,
- shader = renderSession.shaderManager.primitiveShader;
-
- 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 for sure!
-
- // set the matrix transform
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
-
- gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true));
-
- 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
- *
- * @static
- * @private
- * @method updateGraphics
- * @param graphicsData {Graphics} The graphics object to update
- * @param gl {WebGLContext} the current WebGL drawing context
- */
-PIXI.WebGLGraphics.updateGraphics = function(graphics, gl)
-{
- var webGL = graphics._webGL[gl.id];
-
- for (var i = 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, 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
- *
- * @static
- * @private
- * @method buildRectangle
- * @param graphicsData {Graphics} The graphics object containing all the necessary properties
- * @param webGLData {Object}
- */
-PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData)
-{
- // --- //
- // need to convert points to a nice regular data
- //
- var rectData = graphicsData.points;
- var x = rectData[0];
- var y = rectData[1];
- var width = rectData[2];
- var height = rectData[3];
-
-
- if(graphicsData.fill)
- {
- var color = 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
- *
- * @static
- * @private
- * @method buildCircle
- * @param graphicsData {Graphics} The graphics object to draw
- * @param webGLData {Object}
- */
-PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData)
-{
-
- // need to convert points to a nice regular data
- var rectData = graphicsData.points;
- var x = rectData[0];
- var y = rectData[1];
- var width = rectData[2];
- var height = rectData[3];
-
- var totalSegs = 40;
- var seg = (Math.PI * 2) / totalSegs ;
-
- 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
- *
- * @static
- * @private
- * @method buildLine
- * @param graphicsData {Graphics} The graphics object containing all the necessary properties
- * @param webGLData {Object}
- */
-PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData)
-{
- // TODO OPTIMISE!
- var i = 0;
-
- 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 - gonna 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
- *
- * @static
- * @private
- * @method buildPoly
- * @param graphicsData {Graphics} The graphics object containing all the necessary properties
- * @param webGLData {Object}
- */
-PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData)
-{
- var points = graphicsData.points;
- if(points.length < 6)return;
-
- // get first and last point.. figure out the middle!
- var verts = webGLData.points;
- var indices = webGLData.indices;
-
- var length = points.length / 2;
-
- // sort color
- var color = 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.glContexts = []; // this is where we store the webGL contexts for easy access.
-
-/**
- * the WebGLRenderer draws the stage and all its content onto a webGL enabled canvas. This renderer
- * should be used for browsers that support webGL. This Render works by automatically managing webGLBatch's.
- * So no need for Sprite Batch's or Sprite Cloud's
- * Dont forget to add the view to your DOM or you will not see anything :)
- *
- * @class WebGLRenderer
- * @constructor
- * @param width=0 {Number} the width of the canvas view
- * @param height=0 {Number} the height of the canvas view
- * @param view {HTMLCanvasElement} the canvas to use as a view, optional
- * @param transparent=false {Boolean} If the render view is transparent, default false
- * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment)
- *
- */
-PIXI.WebGLRenderer = function(width, height, view, transparent, antialias)
-{
- if(!PIXI.defaultRenderer)PIXI.defaultRenderer = this;
-
- this.type = PIXI.WEBGL_RENDERER;
-
- // do a catch.. only 1 webGL renderer..
- /**
- * Whether the render view is transparent
- *
- * @property transparent
- * @type Boolean
- */
- this.transparent = !!transparent;
-
- /**
- * The width of the canvas view
- *
- * @property width
- * @type Number
- * @default 800
- */
- this.width = width || 800;
-
- /**
- * The height of the canvas view
- *
- * @property height
- * @type Number
- * @default 600
- */
- this.height = height || 600;
-
- /**
- * The canvas element that everything is drawn to
- *
- * @property view
- * @type HTMLCanvasElement
- */
- this.view = view || document.createElement( 'canvas' );
- this.view.width = this.width;
- this.view.height = this.height;
-
- // deal with losing context..
- this.contextLost = this.handleContextLost.bind(this);
- this.contextRestoredLost = this.handleContextRestored.bind(this);
-
- this.view.addEventListener('webglcontextlost', this.contextLost, false);
- this.view.addEventListener('webglcontextrestored', this.contextRestoredLost, false);
-
- this.options = {
- alpha: this.transparent,
- antialias:!!antialias, // SPEED UP??
- premultipliedAlpha:!!transparent,
- stencil:true
- };
-
- //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);
- }
- }
-
- var gl = this.gl;
- this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++;
-
- PIXI.glContexts[this.glContextId] = gl;
-
- if(!PIXI.blendModesWebGL)
- {
- PIXI.blendModesWebGL = [];
-
- 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];
- PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
- }
-
-
-
-
- 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;
-
- // 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;
-
-/**
- * Renders the stage to its webGL view
- *
- * @method render
- * @param stage {Stage} the Stage element to be rendered
- */
-PIXI.WebGLRenderer.prototype.render = function(stage)
-{
- if(this.contextLost)return;
-
-
- // if rendering a new stage clear the batches..
- if(this.__stage !== stage)
- {
- if(stage.interactive)stage.interactionManager.removeEvents();
-
- // 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);
-
- if(this.transparent)
- {
- gl.clearColor(0, 0, 0, 0);
- }
- else
- {
- gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1);
- }
-
-
- gl.clear(gl.COLOR_BUFFER_BIT);
-
- this.renderDisplayObject( stage, this.projection );
-
- // interaction
- if(stage.interactive)
- {
- //need to add some events!
- if(!stage._interactiveEventsAdded)
- {
- stage._interactiveEventsAdded = true;
- stage.interactionManager.setTarget(this);
- }
- }
- else
- {
- if(stage._interactiveEventsAdded)
- {
- stage._interactiveEventsAdded = false;
- 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);
- */
-};
-
-/**
- * Renders a display Object
- *
- * @method renderDIsplayObject
- * @param displayObject {DisplayObject} The DisplayObject to render
- * @param projection {Point} The projection
- * @param buffer {Array} a standard WebGL buffer
- */
-PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer)
-{
- // 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, buffer);
-
- // render the scene!
- displayObject._renderWebGL(this.renderSession);
-
- // finish the sprite batch
- this.spriteBatch.end();
-};
-
-/**
- * Updates the textures loaded into this webgl renderer
- *
- * @static
- * @method updateTextures
- * @private
- */
-PIXI.WebGLRenderer.updateTextures = function()
-{
- var i = 0;
-
- //TODO break this out into a texture manager...
- //for (i = 0; i < PIXI.texturesToUpdate.length; i++)
- // PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]);
-
-
- for (i=0; i < PIXI.Texture.frameUpdates.length; i++)
- PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]);
-
- for (i = 0; i < PIXI.texturesToDestroy.length; i++)
- PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]);
-
- PIXI.texturesToUpdate.length = 0;
- PIXI.texturesToDestroy.length = 0;
- PIXI.Texture.frameUpdates.length = 0;
-};
-
-/**
- * Destroys a loaded webgl texture
- *
- * @method destroyTexture
- * @param texture {Texture} The texture to update
- * @private
- */
-PIXI.WebGLRenderer.destroyTexture = function(texture)
-{
- //TODO break this out into a texture manager...
-
- 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;
-};
-
-/**
- *
- * @method updateTextureFrame
- * @param texture {Texture} The texture to update the frame from
- * @private
- */
-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
- *
- * @method resize
- * @param width {Number} the new width of the webGL view
- * @param height {Number} the new height of the webGL view
- */
-PIXI.WebGLRenderer.prototype.resize = function(width, height)
-{
- this.width = width;
- this.height = height;
-
- this.view.width = width;
- this.view.height = height;
-
- this.gl.viewport(0, 0, this.width, this.height);
-
- this.projection.x = this.width/2;
- this.projection.y = -this.height/2;
-};
-
-/**
- * Creates a WebGL texture
- *
- * @method createWebGLTexture
- * @param texture {Texture} the texture to render
- * @param gl {webglContext} the WebGL context
- * @static
- */
-PIXI.createWebGLTexture = function(texture, gl)
-{
-
-
- 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.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.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];
-};
-
-/**
- * Updates a WebGL texture
- *
- * @method updateWebGLTexture
- * @param texture {Texture} the texture to update
- * @param gl {webglContext} the WebGL context
- * @private
- */
-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.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.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
- *
- * @method handleContextLost
- * @param event {Event}
- * @private
- */
-PIXI.WebGLRenderer.prototype.handleContextLost = function(event)
-{
- event.preventDefault();
- this.contextLost = true;
-};
-
-/**
- * Handles a restored webgl context
- *
- * @method handleContextRestored
- * @param event {Event}
- * @private
- */
-PIXI.WebGLRenderer.prototype.handleContextRestored = function()
-{
-
- //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);
- }
- }
-
- var gl = this.gl;
- gl.id = PIXI.WebGLRenderer.glContextId ++;
-
-
-
- // 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)
- {
- var texture = PIXI.TextureCache[key].baseTexture;
- texture._glTextures = [];
- }
-
- /**
- * Whether the context was lost
- * @property contextLost
- * @type Boolean
- */
- this.contextLost = false;
-
-};
-
-/**
- * Removes everything from the renderer (event listeners, spritebatch, etc...)
- *
- * @method destroy
- */
-PIXI.WebGLRenderer.prototype.destroy = function()
-{
-
- // deal with losing context..
-
- // remove listeners
- this.view.removeEventListener('webglcontextlost', this.contextLost);
- this.view.removeEventListener('webglcontextrestored', this.contextRestoredLost);
-
- PIXI.glContexts[this.glContextId] = null;
-
- this.projection = null;
- this.offset = null;
-
- // time to create the render managers! each one focuses on managine a state in webGL
- this.shaderManager.destroy();
- this.spriteBatch.destroy();
- this.maskManager.destroy();
- this.filterManager.destroy();
-
- this.shaderManager = null;
- this.spriteBatch = null;
- this.maskManager = null;
- this.filterManager = null;
-
- this.gl = null;
- //
- this.renderSession = null;
-};
-
-
-PIXI.WebGLRenderer.glContextId = 0;
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-
-/**
-* @class WebGLMaskManager
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-* @private
-*/
-PIXI.WebGLMaskManager = function(gl)
-{
- this.maskStack = [];
- this.maskPosition = 0;
-
- this.setContext(gl);
-};
-
-/**
-* Sets the drawing context to the one given in parameter
-* @method setContext
-* @param gl {WebGLContext} the current WebGL drawing context
-*/
-PIXI.WebGLMaskManager.prototype.setContext = function(gl)
-{
- this.gl = gl;
-};
-
-/**
-* Applies the Mask and adds it to the current filter stack
-* @method pushMask
-* @param maskData {Array}
-* @param renderSession {RenderSession}
-*/
-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);
-};
-
-/**
-* Removes the last filter from the filter stack and doesn't return it
-* @method popMask
-*
-* @param renderSession {RenderSession} an object containing all the useful parameters
-*/
-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);
-};
-
-/**
-* Destroys the mask stack
-* @method destroy
-*/
-PIXI.WebGLMaskManager.prototype.destroy = function()
-{
- this.maskStack = null;
- this.gl = null;
-};
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
-* @class WebGLShaderManager
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-* @private
-*/
-PIXI.WebGLShaderManager = function(gl)
-{
-
- this.maxAttibs = 10;
- this.attribState = [];
- this.tempAttribState = [];
-
- for (var i = 0; i < this.maxAttibs; i++) {
- this.attribState[i] = false;
- }
-
- this.setContext(gl);
- // the final one is used for the rendering strips
- //this.stripShader = new PIXI.StripShader(gl);
-};
-
-
-/**
-* Initialises the context and the properties
-* @method setContext
-* @param gl {WebGLContext} the current WebGL drawing context
-* @param transparent {Boolean} Whether or not the drawing context should be transparent
-*/
-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);
-
- // this shader is used for the fast sprite rendering
- this.fastShader = new PIXI.PixiFastShader(gl);
-
-
- this.activateShader(this.defaultShader);
-};
-
-
-/**
-* Takes the attributes given in parameters
-* @method setAttribs
-* @param attribs {Array} attribs
-*/
-PIXI.WebGLShaderManager.prototype.setAttribs = function(attribs)
-{
- // reset temp state
-
- var i;
-
- for (i = 0; i < this.tempAttribState.length; i++)
- {
- this.tempAttribState[i] = false;
- }
-
- // set the new attribs
- for (i = 0; i < attribs.length; i++)
- {
- var attribId = attribs[i];
- this.tempAttribState[attribId] = true;
- }
-
- var gl = this.gl;
-
- for (i = 0; i < this.attribState.length; i++)
- {
-
- if(this.attribState[i] !== this.tempAttribState[i])
- {
- this.attribState[i] = this.tempAttribState[i];
-
- if(this.tempAttribState[i])
- {
- gl.enableVertexAttribArray(i);
- }
- else
- {
- gl.disableVertexAttribArray(i);
- }
- }
- }
-};
-
-/**
-* Sets-up the given shader
-*
-* @method activateShader
-* @param shader {Object} the shader that is going to be activated
-*/
-PIXI.WebGLShaderManager.prototype.activateShader = function(shader)
-{
- //if(this.currentShader == shader)return;
-
- this.currentShader = shader;
-
- this.gl.useProgram(shader.program);
- this.setAttribs(shader.attributes);
-
-};
-
-/**
-* Triggers the primitive shader
-* @method activatePrimitiveShader
-*/
-PIXI.WebGLShaderManager.prototype.activatePrimitiveShader = function()
-{
- var gl = this.gl;
-
- gl.useProgram(this.primitiveShader.program);
-
- this.setAttribs(this.primitiveShader.attributes);
-
-};
-
-/**
-* Disable the primitive shader
-* @method deactivatePrimitiveShader
-*/
-PIXI.WebGLShaderManager.prototype.deactivatePrimitiveShader = function()
-{
- var gl = this.gl;
-
- gl.useProgram(this.defaultShader.program);
-
- this.setAttribs(this.defaultShader.attributes);
-};
-
-/**
-* Destroys
-* @method destroy
-*/
-PIXI.WebGLShaderManager.prototype.destroy = function()
-{
- this.attribState = null;
-
- this.tempAttribState = null;
-
- this.primitiveShader.destroy();
-
- this.defaultShader.destroy();
-
- this.fastShader.destroy();
-
- this.gl = null;
-};
-
-
-/**
- * @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
- */
-
- /**
- *
- * @class WebGLSpriteBatch
- * @private
- * @constructor
- * @param gl {WebGLContext} the current WebGL drawing context
- *
- */
-PIXI.WebGLSpriteBatch = function(gl)
-{
-
- /**
- *
- *
- * @property vertSize
- * @type Number
- */
- this.vertSize = 6;
-
- /**
- * The number of images in the SpriteBatch before it flushes
- * @property size
- * @type Number
- */
- this.size = 10000;//Math.pow(2, 16) / this.vertSize;
-
- //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
-
- /**
- * Holds the vertices
- *
- * @property vertices
- * @type Float32Array
- */
- this.vertices = new Float32Array(numVerts);
-
- //index data
- /**
- * Holds the indices
- *
- * @property indices
- * @type Uint16Array
- */
- 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);
-};
-
-/**
-*
-* @method setContext
-*
-* @param gl {WebGLContext} the current WebGL drawing context
-*/
-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;
-};
-
-/**
-*
-* @method begin
-*
-* @param renderSession {RenderSession} the RenderSession
-*/
-PIXI.WebGLSpriteBatch.prototype.begin = function(renderSession)
-{
- this.renderSession = renderSession;
- this.shader = this.renderSession.shaderManager.defaultShader;
-
- this.start();
-};
-
-/**
-*
-* @method end
-*
-*/
-PIXI.WebGLSpriteBatch.prototype.end = function()
-{
- this.flush();
-};
-
-/**
-*
-* @method render
-*
-* @param sprite {Sprite} the sprite to render when using this spritebatch
-*/
-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.trim)
- {
- // 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.width;
- w0 = w1 + width;
-
- h1 = trim.y - aY * trim.height;
- 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;//.toArray();
-
- var a = worldTransform.a;//[0];
- var b = worldTransform.c;//[3];
- var c = worldTransform.b;//[1];
- var d = worldTransform.d;//[4];
- var tx = worldTransform.tx;//[2];
- var ty = worldTransform.ty;///[5];
-
- // xy
- verticies[index++] = a * w1 + c * h1 + tx;
- verticies[index++] = d * h1 + b * w1 + ty;
- // uv
- verticies[index++] = uvs.x0;
- verticies[index++] = uvs.y0;
- // 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.x1;
- verticies[index++] = uvs.y1;
- // 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.x2;
- verticies[index++] = uvs.y2;
- // 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.x3;
- verticies[index++] = uvs.y3;
- // color
- verticies[index++] = alpha;
- verticies[index++] = tint;
-
- // increment the batchsize
- this.currentBatchSize++;
-
-
-};
-
-/**
-* Renders a tilingSprite using the spriteBatch
-* @method renderTilingSprite
-*
-* @param sprite {TilingSprite} the tilingSprite to render
-*/
-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 separate texture so that we can tile part of a texture
-
- if(!tilingSprite._uvs)tilingSprite._uvs = new PIXI.TextureUvs();
-
- var uvs = tilingSprite._uvs;
-
- tilingSprite.tilePosition.x %= texture.baseTexture.width;
- tilingSprite.tilePosition.y %= texture.baseTexture.height;
-
- 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.x0 = 0 - offsetX;
- uvs.y0 = 0 - offsetY;
-
- uvs.x1 = (1 * scaleX) - offsetX;
- uvs.y1 = 0 - offsetY;
-
- uvs.x2 = (1 * scaleX) - offsetX;
- uvs.y2 = (1 * scaleY) - offsetY;
-
- uvs.x3 = 0 - offsetX;
- uvs.y3 = (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.a;//[0];
- var b = worldTransform.c;//[3];
- var c = worldTransform.b;//[1];
- var d = worldTransform.d;//[4];
- var tx = worldTransform.tx;//[2];
- var ty = worldTransform.ty;///[5];
-
- // xy
- verticies[index++] = a * w1 + c * h1 + tx;
- verticies[index++] = d * h1 + b * w1 + ty;
- // uv
- verticies[index++] = uvs.x0;
- verticies[index++] = uvs.y0;
- // 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.x1;
- verticies[index++] = uvs.y1;
- // 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.x2;
- verticies[index++] = uvs.y2;
- // 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.x3;
- verticies[index++] = uvs.y3;
- // color
- verticies[index++] = alpha;
- verticies[index++] = tint;
-
- // increment the batchs
- this.currentBatchSize++;
-};
-
-
-/**
-* Renders the content and empties the current batch
-*
-* @method flush
-*
-*/
-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
-
- if(this.currentBatchSize > ( this.size * 0.5 ) )
- {
- gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
- }
- else
- {
- var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
-
- gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
- }
-
- // 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++;
-};
-
-/**
-*
-* @method stop
-*
-*/
-PIXI.WebGLSpriteBatch.prototype.stop = function()
-{
- this.flush();
-};
-
-/**
-*
-* @method start
-*
-*/
-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);
-
- // 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);
- }
-};
-
-/**
-* Sets-up the given blendMode from WebGL's point of view
-* @method setBlendMode
-*
-* @param blendMode {Number} the blendMode, should be a Pixi const, such as PIXI.BlendModes.ADD
-*/
-PIXI.WebGLSpriteBatch.prototype.setBlendMode = function(blendMode)
-{
- this.flush();
-
- this.currentBlendMode = blendMode;
-
- var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
- this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
-};
-
-/**
-* Destroys the SpriteBatch
-* @method destroy
-*/
-PIXI.WebGLSpriteBatch.prototype.destroy = function()
-{
-
- this.vertices = null;
- this.indices = null;
-
- this.gl.deleteBuffer( this.vertexBuffer );
- this.gl.deleteBuffer( this.indexBuffer );
-
- this.currentBaseTexture = null;
-
- this.gl = null;
-};
-
-
-/**
- * @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.WebGLFastSpriteBatch = function(gl)
-{
-
-
- this.vertSize = 10;
- this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize;
- this.size = this.maxSize;
-
- //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.maxSize * 6;
-
- //vertex data
- this.vertices = new Float32Array(numVerts);
- //index data
- this.indices = new Uint16Array(numIndices);
-
- this.vertexBuffer = null;
- this.indexBuffer = null;
-
- 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.currentBlendMode = 0;
- this.renderSession = null;
-
-
- this.shader = null;
-
- this.matrix = null;
-
- this.setContext(gl);
-};
-
-PIXI.WebGLFastSpriteBatch.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.WebGLFastSpriteBatch.prototype.begin = function(spriteBatch, renderSession)
-{
- this.renderSession = renderSession;
- this.shader = this.renderSession.shaderManager.fastShader;
-
- this.matrix = spriteBatch.worldTransform.toArray(true);
-
- this.start();
-};
-
-PIXI.WebGLFastSpriteBatch.prototype.end = function()
-{
- this.flush();
-};
-
-
-PIXI.WebGLFastSpriteBatch.prototype.render = function(spriteBatch)
-{
-
- var children = spriteBatch.children;
- var sprite = children[0];
-
- // if the uvs have not updated then no point rendering just yet!
-
- // check texture.
- if(!sprite.texture._uvs)return;
-
- this.currentBaseTexture = sprite.texture.baseTexture;
- // check blend mode
- if(sprite.blendMode !== this.currentBlendMode)
- {
- this.setBlendMode(sprite.blendMode);
- }
-
- for(var i=0,j= children.length; i= this.size)
- {
- this.flush();
- }
-};
-
-PIXI.WebGLFastSpriteBatch.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
-
- if(!this.currentBaseTexture._glTextures[gl.id])PIXI.createWebGLTexture(this.currentBaseTexture, gl);
-
- gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]);// || PIXI.createWebGLTexture(this.currentBaseTexture, gl));
-
- // upload the verts to the buffer
-
-
- if(this.currentBatchSize > ( this.size * 0.5 ) )
- {
- gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
- }
- else
- {
- 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.WebGLFastSpriteBatch.prototype.stop = function()
-{
- this.flush();
-};
-
-PIXI.WebGLFastSpriteBatch.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);
-
- // set the projection
- var projection = this.renderSession.projection;
- gl.uniform2f(this.shader.projectionVector, projection.x, projection.y);
-
- // set the matrix
- gl.uniformMatrix3fv(this.shader.uMatrix, false, this.matrix);
-
- // set the pointers
- var stride = this.vertSize * 4;
-
- gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
- gl.vertexAttribPointer(this.shader.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4);
- gl.vertexAttribPointer(this.shader.aScale, 2, gl.FLOAT, false, stride, 4 * 4);
- gl.vertexAttribPointer(this.shader.aRotation, 1, gl.FLOAT, false, stride, 6 * 4);
- gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4);
- gl.vertexAttribPointer(this.shader.colorAttribute, 1, gl.FLOAT, false, stride, 9 * 4);
-
- // set the blend mode..
- if(this.currentBlendMode !== PIXI.blendModes.NORMAL)
- {
- this.setBlendMode(PIXI.blendModes.NORMAL);
- }
-};
-
-PIXI.WebGLFastSpriteBatch.prototype.setBlendMode = function(blendMode)
-{
- this.flush();
-
- this.currentBlendMode = blendMode;
-
- var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
- this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
-};
-
-
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
-* @class WebGLFilterManager
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-* @param transparent {Boolean} Whether or not the drawing context should be transparent
-* @private
-*/
-PIXI.WebGLFilterManager = function(gl, transparent)
-{
- this.transparent = transparent;
-
- this.filterStack = [];
-
- this.offsetX = 0;
- this.offsetY = 0;
-
- this.setContext(gl);
-};
-
-// API
-/**
-* Initialises the context and the properties
-* @method setContext
-* @param gl {WebGLContext} the current WebGL drawing context
-*/
-PIXI.WebGLFilterManager.prototype.setContext = function(gl)
-{
- this.gl = gl;
- this.texturePool = [];
-
- this.initShaderBuffers();
-};
-
-/**
-*
-* @method begin
-* @param renderSession {RenderSession}
-* @param buffer {ArrayBuffer}
-*/
-PIXI.WebGLFilterManager.prototype.begin = function(renderSession, buffer)
-{
- this.renderSession = renderSession;
- this.defaultShader = renderSession.shaderManager.defaultShader;
-
- var projection = this.renderSession.projection;
-
- this.width = projection.x * 2;
- this.height = -projection.y * 2;
- this.buffer = buffer;
-};
-
-/**
-* Applies the filter and adds it to the current filter stack
-* @method pushFilter
-* @param filterBlock {Object} the filter that will be pushed to the current filter stack
-*/
-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);
-
- filterBlock.target.filterArea = filterBlock.target.getBounds();
-
- 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);
-
- // 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;
-
- // update projection
- gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2);
- gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y);
-
- gl.colorMask(true, true, true, true);
- gl.clearColor(0,0,0, 0);
- gl.clear(gl.COLOR_BUFFER_BIT);
-
- filterBlock._glFilterTexture = texture;
-
-};
-
-
-/**
-* Removes the last filter from the filter stack and doesn't return it
-* @method popFilter
-*/
-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);
- // now 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 previous 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!
- 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;
-};
-
-
-/**
-* Applies the filter to the specified area
-* @method applyFilterPass
-* @param filter {AbstractFilter} the filter that needs to be applied
-* @param filterArea {texture} TODO - might need an update
-* @param width {Number} the horizontal range of the filter
-* @param height {Number} the vertical range of the filter
-*/
-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)
- {
- 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;
- }
-
- 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++;
-};
-
-/**
-* Initialises the shader buffers
-* @method initShaderBuffers
-*/
-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 reference 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);
-};
-
-/**
-* Destroys the filter and removes it from the filter stack
-* @method destroy
-*/
-PIXI.WebGLFilterManager.prototype.destroy = function()
-{
- var gl = this.gl;
-
- this.filterStack = null;
-
- this.offsetX = 0;
- this.offsetY = 0;
-
- // destroy textures
- for (var i = 0; i < this.texturePool.length; i++) {
- this.texturePool.destroy();
- }
-
- this.texturePool = null;
-
- //destroy buffers..
- gl.deleteBuffer(this.vertexBuffer);
- gl.deleteBuffer(this.uvBuffer);
- gl.deleteBuffer(this.colorBuffer);
- gl.deleteBuffer(this.indexBuffer);
-};
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
-* @class FilterTexture
-* @constructor
-* @param gl {WebGLContext} the current WebGL drawing context
-* @param width {Number} the horizontal range of the filter
-* @param height {Number} the vertical range of the filter
-* @private
-*/
-PIXI.FilterTexture = function(gl, width, height)
-{
- /**
- * @property gl
- * @type WebGLContext
- */
- 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);
-};
-
-
-/**
-* Clears the filter texture
-* @method clear
-*/
-PIXI.FilterTexture.prototype.clear = function()
-{
- var gl = this.gl;
-
- gl.clearColor(0,0,0, 0);
- gl.clear(gl.COLOR_BUFFER_BIT);
-};
-
-/**
- * Resizes the texture to the specified width and height
- *
- * @method resize
- * @param width {Number} the new width of the texture
- * @param height {Number} the new height of the texture
- */
-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);
-
-};
-
-/**
-* Destroys the filter texture
-* @method destroy
-*/
-PIXI.FilterTexture.prototype.destroy = function()
-{
- var gl = this.gl;
- gl.deleteFramebuffer( this.frameBuffer );
- gl.deleteTexture( this.texture );
-
- this.frameBuffer = null;
- this.texture = null;
-};
-
-/**
- * @author Mat Groves
- *
- *
- */
-/**
- * A set of functions used to handle masking
- *
- * @class CanvasMaskManager
- */
-PIXI.CanvasMaskManager = function()
-{
-
-};
-
-/**
- * This method adds it to the current stack of masks
- *
- * @method pushMask
- * @param maskData the maskData that will be pushed
- * @param context {Context2D} the 2d drawing method of the canvas
- */
-PIXI.CanvasMaskManager.prototype.pushMask = function(maskData, context)
-{
- context.save();
-
- var cacheAlpha = maskData.alpha;
- var transform = maskData.worldTransform;
-
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
-
- PIXI.CanvasGraphics.renderGraphicsMask(maskData, context);
-
- context.clip();
-
- maskData.worldAlpha = cacheAlpha;
-};
-
-/**
- * Restores the current drawing context to the state it was before the mask was applied
- *
- * @method popMask
- * @param context {Context2D} the 2d drawing method of the canvas
- */
-PIXI.CanvasMaskManager.prototype.popMask = function(context)
-{
- context.restore();
-};
-
-/**
- * @author Mat Groves
- *
- *
- */
-
-/**
- * @class CanvasTinter
- * @constructor
- * @static
- */
-PIXI.CanvasTinter = function()
-{
- /// this.textureCach
-};
-
-//PIXI.CanvasTinter.cachTint = true;
-
-
-/**
- * Basically this method just needs a sprite and a color and tints the sprite
- * with the given color
- *
- * @method getTintedTexture
- * @param sprite {Sprite} the sprite to tint
- * @param color {Number} the color to use to tint the sprite with
- */
-PIXI.CanvasTinter.getTintedTexture = function(sprite, color)
-{
-
- 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 reference to the canvas
- PIXI.CanvasTinter.canvas = null;
-
- }
-
- return canvas;
-};
-
-/**
- * Tint a texture using the "multiply" operation
- * @method tintWithMultiply
- * @param texture {texture} the texture to tint
- * @param color {Number} the color to use to tint the sprite with
- * @param canvas {HTMLCanvasElement} the current 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);
-};
-
-/**
- * Tint a texture using the "overlay" operation
- * @method tintWithOverlay
- * @param texture {texture} the texture to tint
- * @param color {Number} the color to use to tint the sprite with
- * @param canvas {HTMLCanvasElement} the current canvas
- */
-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";
-
-};
-
-/**
- * Tint a texture pixel per pixel
- * @method tintPerPixel
- * @param texture {texture} the texture to tint
- * @param color {Number} the color to use to tint the sprite with
- * @param canvas {HTMLCanvasElement} the current canvas
- */
-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);
-};
-
-/**
- * Rounds the specified color according to the PIXI.CanvasTinter.cacheStepsPerColorChannel
- * @method roundColor
- * @param color {number} the color to round, should be a hex color
- */
-PIXI.CanvasTinter.roundColor = function(color)
-{
- var step = PIXI.CanvasTinter.cacheStepsPerColorChannel;
-
- var rgbValues = PIXI.hex2rgb(color);
-
- rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step);
- rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step);
- rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step);
-
- return PIXI.rgb2hex(rgbValues);
-};
-
-/**
- *
- * Number of steps which will be used as a cap when rounding colors
- *
- * @property cacheStepsPerColorChannel
- * @type Number
- */
-PIXI.CanvasTinter.cacheStepsPerColorChannel = 8;
-/**
- *
- * Number of steps which will be used as a cap when rounding colors
- *
- * @property convertTintToImage
- * @type Boolean
- */
-PIXI.CanvasTinter.convertTintToImage = false;
-
-/**
- * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method
- *
- * @property canUseMultiply
- * @type Boolean
- */
-PIXI.CanvasTinter.canUseMultiply = PIXI.canUseNewCanvasBlendModes();
-
-PIXI.CanvasTinter.tintMethod = PIXI.CanvasTinter.canUseMultiply ? PIXI.CanvasTinter.tintWithMultiply : PIXI.CanvasTinter.tintWithPerPixel;
-
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
- * Dont forget to add the view to your DOM or you will not see anything :)
- *
- * @class CanvasRenderer
- * @constructor
- * @param width=800 {Number} the width of the canvas view
- * @param height=600 {Number} the height of the canvas view
- * @param [view] {HTMLCanvasElement} the canvas to use as a view, optional
- * @param [transparent=false] {Boolean} the transparency of the render view, default false
- */
-PIXI.CanvasRenderer = function(width, height, view, transparent)
-{
- PIXI.defaultRenderer = PIXI.defaultRenderer || this;
-
- this.type = PIXI.CANVAS_RENDERER;
-
- /**
- * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.
- * If the Stage is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color.
- * If the Stage is transparent Pixi will use clearRect to clear the canvas every frame.
- * Disable this by setting this to false. For example if your game has a canvas filling background image you often don't need this set.
- *
- * @property clearBeforeRender
- * @type Boolean
- * @default
- */
- this.clearBeforeRender = true;
-
- /**
- * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
- * Handy for crisp pixel art and speed on legacy devices.
- *
- * @property roundPixels
- * @type Boolean
- * @default
- */
- this.roundPixels = false;
-
- /**
- * Whether the render view is transparent
- *
- * @property transparent
- * @type Boolean
- */
- this.transparent = !!transparent;
-
- 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";
- PIXI.blendModesCanvas[PIXI.blendModes.OVERLAY] = "overlay";
- PIXI.blendModesCanvas[PIXI.blendModes.DARKEN] = "darken";
- PIXI.blendModesCanvas[PIXI.blendModes.LIGHTEN] = "lighten";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR_DODGE] = "color-dodge";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR_BURN] = "color-burn";
- PIXI.blendModesCanvas[PIXI.blendModes.HARD_LIGHT] = "hard-light";
- PIXI.blendModesCanvas[PIXI.blendModes.SOFT_LIGHT] = "soft-light";
- PIXI.blendModesCanvas[PIXI.blendModes.DIFFERENCE] = "difference";
- PIXI.blendModesCanvas[PIXI.blendModes.EXCLUSION] = "exclusion";
- PIXI.blendModesCanvas[PIXI.blendModes.HUE] = "hue";
- PIXI.blendModesCanvas[PIXI.blendModes.SATURATION] = "saturation";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR] = "color";
- PIXI.blendModesCanvas[PIXI.blendModes.LUMINOSITY] = "luminosity";
- }
- 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";
- PIXI.blendModesCanvas[PIXI.blendModes.OVERLAY] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.DARKEN] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.LIGHTEN] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR_DODGE] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR_BURN] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.HARD_LIGHT] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.SOFT_LIGHT] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.DIFFERENCE] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.EXCLUSION] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.HUE] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.SATURATION] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.COLOR] = "source-over";
- PIXI.blendModesCanvas[PIXI.blendModes.LUMINOSITY] = "source-over";
- }
- }
-
- /**
- * 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 everything is drawn to
- *
- * @property view
- * @type HTMLCanvasElement
- */
- this.view = view || document.createElement( "canvas" );
-
- /**
- * The canvas 2d context that everything is drawn with
- * @property context
- * @type HTMLCanvasElement 2d Context
- */
- this.context = this.view.getContext( "2d", { alpha: this.transparent } );
-
- 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;
-
- /**
- * Instance of a PIXI.CanvasMaskManager, handles masking when using the canvas renderer
- * @property CanvasMaskManager
- * @type CanvasMaskManager
- */
- this.maskManager = new PIXI.CanvasMaskManager();
-
- /**
- * The render session is just a bunch of parameter used for rendering
- * @property renderSession
- * @type Object
- */
- this.renderSession = {
- context: this.context,
- maskManager: this.maskManager,
- scaleMode: null,
- smoothProperty: null
- };
-
- if("imageSmoothingEnabled" in this.context)
- this.renderSession.smoothProperty = "imageSmoothingEnabled";
- else if("webkitImageSmoothingEnabled" in this.context)
- this.renderSession.smoothProperty = "webkitImageSmoothingEnabled";
- else if("mozImageSmoothingEnabled" in this.context)
- this.renderSession.smoothProperty = "mozImageSmoothingEnabled";
- else if("oImageSmoothingEnabled" in this.context)
- this.renderSession.smoothProperty = "oImageSmoothingEnabled";
-};
-
-// constructor
-PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer;
-
-/**
- * Renders the stage to its canvas view
- *
- * @method render
- * @param stage {Stage} the Stage element to be rendered
- */
-PIXI.CanvasRenderer.prototype.render = function(stage)
-{
- // update textures if need be
- PIXI.texturesToUpdate.length = 0;
- PIXI.texturesToDestroy.length = 0;
-
- stage.updateTransform();
-
- this.context.setTransform(1,0,0,1,0,0);
- this.context.globalAlpha = 1;
-
- if (!this.transparent && this.clearBeforeRender)
- {
- this.context.fillStyle = stage.backgroundColorString;
- this.context.fillRect(0, 0, this.width, this.height);
- }
- else if (this.transparent && this.clearBeforeRender)
- {
- this.context.clearRect(0, 0, this.width, this.height);
- }
-
- this.renderDisplayObject(stage);
-
- // 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.length = 0;
- }
-};
-
-/**
- * Resizes the canvas view to the specified width and height
- *
- * @method resize
- * @param width {Number} the new width of the canvas view
- * @param height {Number} the new height of the canvas view
- */
-PIXI.CanvasRenderer.prototype.resize = function(width, height)
-{
- this.width = width;
- this.height = height;
-
- this.view.width = width;
- this.view.height = height;
-};
-
-/**
- * Renders a display object
- *
- * @method renderDisplayObject
- * @param displayObject {DisplayObject} The displayObject to render
- * @param context {Context2D} the context 2d method of the canvas
- * @private
- */
-PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject, context)
-{
- // no longer recursive!
- //var transform;
- //var context = this.context;
-
- this.renderSession.context = context || this.context;
- displayObject._renderCanvas(this.renderSession);
-};
-
-/**
- * Renders a flat strip
- *
- * @method renderStripFlat
- * @param strip {Strip} The Strip to render
- * @private
- */
-PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip)
-{
- var context = this.context;
- var verticies = strip.verticies;
-
- var 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
- *
- * @method renderStrip
- * @param strip {Strip} The Strip to render
- * @private
- */
-PIXI.CanvasRenderer.prototype.renderStrip = function(strip)
-{
- var context = this.context;
-
- // draw triangles!!
- var verticies = strip.verticies;
- var uvs = strip.uvs;
-
- var length = verticies.length/2;
- this.count++;
-
- for (var i = 1; i < length-2; i++)
- {
- // draw some triangles!
- var index = i*2;
-
- var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4];
- var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5];
-
- var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width;
- var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height;
-
- context.save();
- context.beginPath();
- context.moveTo(x0, y0);
- context.lineTo(x1, y1);
- context.lineTo(x2, y2);
- context.closePath();
-
- context.clip();
-
- // Compute matrix transform
- var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2;
- var 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();
- }
-};
-
-/**
- * Creates a Canvas element of the given size
- *
- * @method CanvasBuffer
- * @param width {Number} the width for the newly created canvas
- * @param height {Number} the height for the newly created canvas
- * @static
- * @private
- */
-PIXI.CanvasBuffer = function(width, height)
-{
- this.width = width;
- this.height = height;
-
- this.canvas = document.createElement( "canvas" );
- this.context = this.canvas.getContext( "2d" );
-
- this.canvas.width = width;
- this.canvas.height = height;
-};
-
-/**
- * Clears the canvas that was created by the CanvasBuffer class
- *
- * @method clear
- * @private
- */
-PIXI.CanvasBuffer.prototype.clear = function()
-{
- this.context.clearRect(0,0, this.width, this.height);
-};
-
-/**
- * Resizes the canvas that was created by the CanvasBuffer class to the specified width and height
- *
- * @method resize
- * @param width {Number} the new width of the canvas
- * @param height {Number} the new height of the canvas
- * @private
- */
-
-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
- */
-
-
-/**
- * A set of functions used by the canvas renderer to draw the primitive graphics data
- *
- * @class CanvasGraphics
- */
-PIXI.CanvasGraphics = function()
-{
-
-};
-
-
-/*
- * Renders the graphics object
- *
- * @static
- * @private
- * @method renderGraphics
- * @param graphics {Graphics} the actual graphics object to render
- * @param context {Context2D} the 2d drawing method of the canvas
- */
-PIXI.CanvasGraphics.renderGraphics = function(graphics, context)
-{
- var worldAlpha = graphics.worldAlpha;
- var color = '';
-
- 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
- *
- * @static
- * @private
- * @method renderGraphicsMask
- * @param graphics {Graphics} the graphics which will be used as a mask
- * @param context {Context2D} the context 2d method of the canvas
- */
-PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context)
-{
- 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
- */
-
-
-/**
- * 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 polygons can be filled at this stage
- * Complex polygons will not be filled. Heres an example of a complex polygon: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png
- *
- * @class Graphics
- * @extends DisplayObjectContainer
- * @constructor
- */
-PIXI.Graphics = function()
-{
- PIXI.DisplayObjectContainer.call( this );
-
- this.renderable = true;
-
- /**
- * The alpha of the fill of this graphics object
- *
- * @property fillAlpha
- * @type Number
- */
- this.fillAlpha = 1;
-
- /**
- * The width of any lines drawn
- *
- * @property lineWidth
- * @type Number
- */
- this.lineWidth = 0;
-
- /**
- * The color of any lines drawn
- *
- * @property lineColor
- * @type String
- */
- this.lineColor = "black";
-
- /**
- * Graphics data
- *
- * @property graphicsData
- * @type Array
- * @private
- */
- this.graphicsData = [];
-
-
- /**
- * The tint applied to the graphic shape. This is a hex value
- *
- * @property tint
- * @type Number
- * @default 0xFFFFFF
- */
- this.tint = 0xFFFFFF;// * Math.random();
-
- /**
- * The blend mode to be applied to the graphic shape
- *
- * @property blendMode
- * @type Number
- * @default PIXI.blendModes.NORMAL;
- */
- this.blendMode = PIXI.blendModes.NORMAL;
-
- /**
- * Current path
- *
- * @property currentPath
- * @type Object
- * @private
- */
- this.currentPath = {points:[]};
-
- /**
- * Array containing some WebGL-related properties used by the WebGL renderer
- *
- * @property _webGL
- * @type Array
- * @private
- */
- this._webGL = [];
-
- /**
- * Whether this shape is being used as a mask
- *
- * @property isMask
- * @type isMask
- */
- this.isMask = false;
-
- /**
- * The bounds of the graphic shape as rectangle object
- *
- * @property bounds
- * @type Rectangle
- */
- this.bounds = null;
-
- /**
- * the bounds' padding used for bounds calculation
- *
- * @property bounds
- * @type Number
- */
- 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 antialiased because it will be rendered using canvas
- * Not recommended if you are constanly 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 the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method.
- *
- * @method lineStyle
- * @param lineWidth {Number} width of the line to draw, will update the object's stored style
- * @param color {Number} color of the line to draw, will update the object's stored style
- * @param alpha {Number} alpha of the line to draw, will update the object's stored style
- */
-PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha)
-{
- if (!this.currentPath.points.length) 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);
-
- return this;
-};
-
-/**
- * Moves the current drawing position to (x, y).
- *
- * @method moveTo
- * @param x {Number} the X coordinate to move to
- * @param y {Number} the Y coordinate to move to
- */
-PIXI.Graphics.prototype.moveTo = function(x, y)
-{
- 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);
-
- return this;
-};
-
-/**
- * Draws a line using the current line style from the current drawing position to (x, y);
- * the current drawing position is then set to (x, y).
- *
- * @method lineTo
- * @param x {Number} the X coordinate to draw to
- * @param y {Number} the Y coordinate to draw to
- */
-PIXI.Graphics.prototype.lineTo = function(x, y)
-{
- this.currentPath.points.push(x, y);
- this.dirty = true;
-
- return this;
-};
-
-/**
- * Specifies a simple one-color fill that subsequent calls to other Graphics methods
- * (such as lineTo() or drawCircle()) use when drawing.
- *
- * @method beginFill
- * @param color {Number} the color of the fill
- * @param alpha {Number} the alpha of the fill
- */
-PIXI.Graphics.prototype.beginFill = function(color, alpha)
-{
-
- this.filling = true;
- this.fillColor = color || 0;
- this.fillAlpha = (arguments.length < 2) ? 1 : alpha;
-
- return this;
-};
-
-/**
- * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method.
- *
- * @method endFill
- */
-PIXI.Graphics.prototype.endFill = function()
-{
- this.filling = false;
- this.fillColor = null;
- this.fillAlpha = 1;
-
- return this;
-};
-
-/**
- * @method drawRect
- *
- * @param x {Number} The X coord of the top-left of the rectangle
- * @param y {Number} The Y coord of the top-left of the rectangle
- * @param width {Number} The width of the rectangle
- * @param height {Number} The height of the rectangle
- */
-PIXI.Graphics.prototype.drawRect = function( x, y, width, height )
-{
- if (!this.currentPath.points.length) 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;
-
- return this;
-};
-
-/**
- * Draws a circle.
- *
- * @method drawCircle
- * @param x {Number} The X coordinate of the center of the circle
- * @param y {Number} The Y coordinate of the center of the circle
- * @param radius {Number} The radius of the circle
- */
-PIXI.Graphics.prototype.drawCircle = function( x, y, radius)
-{
-
- if (!this.currentPath.points.length) 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;
-
- return this;
-};
-
-/**
- * Draws an ellipse.
- *
- * @method drawEllipse
- * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this ellipse
- * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this ellipse
- * @param width {Number} The width of the ellipse
- * @param height {Number} The height of the ellipse
- */
-PIXI.Graphics.prototype.drawEllipse = function( x, y, width, height)
-{
-
- 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;
-
- return this;
-};
-
-/**
- * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings.
- *
- * @method clear
- */
-PIXI.Graphics.prototype.clear = function()
-{
- this.lineWidth = 0;
- this.filling = false;
-
- this.dirty = true;
- this.clearDirty = true;
- this.graphicsData = [];
-
- this.bounds = null; //new PIXI.Rectangle();
-
- return this;
-};
-
-/**
- * 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;
-};
-
-/**
-* Renders the object using the WebGL renderer
-*
-* @method _renderWebGL
-* @param renderSession {RenderSession}
-* @private
-*/
-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)
- {
- renderSession.spriteBatch.currentBlendMode = this.blendMode;
- var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode];
- renderSession.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
- }
-
- PIXI.WebGLGraphics.renderGraphics(this, renderSession);
-
- // only render if 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;
-};
-
-/**
- * Update the bounds of the object
- *
- * @method updateBounds
- */
-PIXI.Graphics.prototype.updateBounds = function()
-{
-
- var minX = Infinity;
- var maxX = -Infinity;
-
- var minY = Infinity;
- var maxY = -Infinity;
-
- var points, x, y, w, h;
-
- 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[0] - lineWidth/2;
- y = points[1] - lineWidth/2;
- w = points[2] + lineWidth;
- h = points[3] + lineWidth;
-
- minX = x < minX ? x : minX;
- maxX = x + w > maxX ? x + w : maxX;
-
- minY = y < minY ? x : minY;
- maxY = y + h > maxY ? y + h : maxY;
- }
- else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP)
- {
- x = points[0];
- y = points[1];
- w = points[2] + lineWidth/2;
- h = points[3] + lineWidth/2;
-
- minX = x - w < minX ? x - w : minX;
- maxX = x + w > maxX ? x + w : maxX;
-
- minY = y - h < minY ? y - h : minY;
- maxY = y + h > maxY ? y + h : 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);
-};
-
-
-/**
- * Generates the cached sprite when the sprite has cacheAsBitmap = true
- *
- * @method _generateCachedSprite
- * @private
- */
-PIXI.Graphics.prototype._generateCachedSprite = function()
-{
- var bounds = this.getLocalBounds();
-
- 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 offset 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;
-PIXI.Graphics.RECT = 1;
-PIXI.Graphics.CIRC = 2;
-PIXI.Graphics.ELIP = 3;
-
-/**
- * @author Mat Groves http://matgroves.com/
- */
-
- /**
- *
- * @class Strip
- * @extends DisplayObjectContainer
- * @constructor
- * @param texture {Texture} The texture to use
- * @param width {Number} the width
- * @param height {Number} the height
- *
- */
-PIXI.Strip = function(texture, width, height)
-{
- PIXI.DisplayObjectContainer.call( this );
- this.texture = texture;
- this.blendMode = PIXI.blendModes.NORMAL;
-
- try
- {
- this.uvs = new Float32Array([0, 1,
- 1, 1,
- 1, 0, 0,1]);
-
- this.verticies = new Float32Array([0, 0,
- 0,0,
- 0,0, 0,
- 0, 0]);
-
- this.colors = new Float32Array([1, 1, 1, 1]);
-
- this.indices = new Uint16Array([0, 1, 2, 3]);
- }
- catch(error)
- {
- this.uvs = [0, 1,
- 1, 1,
- 1, 0, 0,1];
-
- this.verticies = [0, 0,
- 0,0,
- 0,0, 0,
- 0, 0];
-
- this.colors = [1, 1, 1, 1];
-
- this.indices = [0, 1, 2, 3];
- }
-
-
- /*
- this.uvs = new Float32Array()
- this.verticies = new Float32Array()
- this.colors = new Float32Array()
- this.indices = new Uint16Array()
- */
-
- this.width = width;
- this.height = height;
-
- // load the texture!
- if(texture.baseTexture.hasLoaded)
- {
- this.width = this.texture.frame.width;
- this.height = this.texture.frame.height;
- this.updateFrame = true;
- }
- else
- {
- this.onTextureUpdateBind = this.onTextureUpdate.bind(this);
- this.texture.addEventListener( 'update', this.onTextureUpdateBind );
- }
-
- this.renderable = true;
-};
-
-// constructor
-PIXI.Strip.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
-PIXI.Strip.prototype.constructor = PIXI.Strip;
-
-/*
- * Sets the texture that the Strip will use
- *
- * @method setTexture
- * @param texture {Texture} the texture that will be used
- * @private
- */
-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;
-};
-
-/**
- * When the texture is updated, this event will fire to update the scale and frame
- *
- * @method onTextureUpdate
- * @param event
- * @private
- */
-PIXI.Strip.prototype.onTextureUpdate = function()
-{
- this.updateFrame = true;
-};
-/* @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- *
- * @class Rope
- * @constructor
- * @param texture {Texture} The texture to use
- * @param points {Array}
- *
- */
-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 = 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
-PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype );
-PIXI.Rope.prototype.constructor = PIXI.Rope;
-
-/*
- * Refreshes
- *
- * @method refresh
- */
-PIXI.Rope.prototype.refresh = function()
-{
- 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;
- }
-};
-
-/*
- * Updates the object transform for rendering
- *
- * @method updateTransform
- * @private
- */
-PIXI.Rope.prototype.updateTransform = function()
-{
-
- 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 );
-};
-/*
- * Sets the texture that the Rope will use
- *
- * @method setTexture
- * @param texture {Texture} the texture that will be used
- */
-PIXI.Rope.prototype.setTexture = function(texture)
-{
- // stop current texture
- this.texture = texture;
- this.updateFrame = true;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/
- */
-
-/**
- * A tiling sprite is a fast way of rendering a tiling image
- *
- * @class TilingSprite
- * @extends DisplayObjectContainer
- * @constructor
- * @param texture {Texture} the texture of the tiling sprite
- * @param width {Number} the width of the tiling sprite
- * @param height {Number} the height of the tiling sprite
- */
-PIXI.TilingSprite = function(texture, width, height)
-{
- PIXI.Sprite.call( this, texture);
-
- /**
- * The with of the tiling sprite
- *
- * @property width
- * @type Number
- */
- this.width = width || 100;
- /**
- * The height of the tiling sprite
- *
- * @property height
- * @type Number
- */
- this.height = height || 100;
-
- /**
- * The scaling of the image that is being tiled
- *
- * @property tileScale
- * @type Point
- */
- this.tileScale = new PIXI.Point(1,1);
-
- /**
- * A point that represents the scale of the texture object
- *
- * @property tileScaleOffset
- * @type Point
- */
- 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);
-
-
- /**
- * Whether this sprite is renderable or not
- *
- * @property renderable
- * @type Boolean
- * @default true
- */
- this.renderable = true;
-
- /**
- * The tint applied to the sprite. This is a hex value
- *
- * @property tint
- * @type Number
- * @default 0xFFFFFF
- */
- this.tint = 0xFFFFFF;
-
- /**
- * The blend mode to be applied to the sprite
- *
- * @property blendMode
- * @type Number
- * @default PIXI.blendModes.NORMAL;
- */
- this.blendMode = PIXI.blendModes.NORMAL;
-};
-
-// constructor
-PIXI.TilingSprite.prototype = Object.create(PIXI.Sprite.prototype);
-PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite;
-
-
-/**
- * The width of the sprite, setting this will actually modify the scale to achieve the value set
- *
- * @property width
- * @type Number
- */
-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 achieve the value set
- *
- * @property height
- * @type Number
- */
-Object.defineProperty(PIXI.TilingSprite.prototype, 'height', {
- get: function() {
- return this._height;
- },
- set: function(value) {
- this._height = value;
- }
-});
-
-/**
- * When the texture is updated, this event will be fired to update the scale and frame
- *
- * @method onTextureUpdate
- * @param event
- * @private
- */
-PIXI.TilingSprite.prototype.onTextureUpdate = function()
-{
- this.updateFrame = true;
-};
-
-/**
-* Renders the object using the WebGL renderer
-*
-* @method _renderWebGL
-* @param renderSession {RenderSession}
-* @private
-*/
-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);
- 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 reference so that if this function gets called again in the render cycle we do not have to recalculate
- this._currentBounds = bounds;
-
- return bounds;
-};
-
-/**
-*
-* @method generateTilingTexture
-*
-* @param forcePowerOfTwo {Boolean} Whether we want to force the texture to be a power of two
-*/
-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
- *
- * Awesome JS run time provided by EsotericSoftware
- * https://github.com/EsotericSoftware/spine-runtimes
- *
- */
-
-/*
- * 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
- * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source
- *
- * @class Spine
- * @extends DisplayObjectContainer
- * @constructor
- * @param url {String} The url of the spine anim file to be used
- */
-PIXI.Spine = function (url) {
- PIXI.DisplayObjectContainer.call(this);
-
- this.spineData = PIXI.AnimCache[url];
-
- if (!this.spineData) {
- throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url);
- }
-
- this.skeleton = new spine.Skeleton(this.spineData);
- this.skeleton.updateWorldTransform();
-
- this.stateData = new spine.AnimationStateData(this.spineData);
- this.state = new spine.AnimationState(this.stateData);
-
- this.slotContainers = [];
-
- for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) {
- var slot = this.skeleton.drawOrder[i];
- var attachment = slot.attachment;
- var slotContainer = new PIXI.DisplayObjectContainer();
- this.slotContainers.push(slotContainer);
- this.addChild(slotContainer);
- if (!(attachment instanceof spine.RegionAttachment)) {
- continue;
- }
- var spriteName = attachment.rendererObject.name;
- var sprite = this.createSprite(slot, attachment.rendererObject);
- slot.currentSprite = sprite;
- slot.currentSpriteName = spriteName;
- slotContainer.addChild(sprite);
- }
-};
-
-PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
-PIXI.Spine.prototype.constructor = PIXI.Spine;
-
-/*
- * Updates the object transform for rendering
- *
- * @method updateTransform
- * @private
- */
-PIXI.Spine.prototype.updateTransform = function () {
- this.lastTime = this.lastTime || Date.now();
- var timeDelta = (Date.now() - this.lastTime) * 0.001;
- this.lastTime = Date.now();
- this.state.update(timeDelta);
- this.state.apply(this.skeleton);
- this.skeleton.updateWorldTransform();
-
- var drawOrder = this.skeleton.drawOrder;
- for (var i = 0, n = drawOrder.length; i < n; i++) {
- var slot = drawOrder[i];
- var attachment = slot.attachment;
- var slotContainer = this.slotContainers[i];
- if (!(attachment instanceof spine.RegionAttachment)) {
- slotContainer.visible = false;
- continue;
- }
-
- if (attachment.rendererObject) {
- if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) {
- var spriteName = attachment.rendererObject.name;
- if (slot.currentSprite !== undefined) {
- slot.currentSprite.visible = false;
- }
- slot.sprites = slot.sprites || {};
- if (slot.sprites[spriteName] !== undefined) {
- slot.sprites[spriteName].visible = true;
- } else {
- var sprite = this.createSprite(slot, attachment.rendererObject);
- slotContainer.addChild(sprite);
- }
- slot.currentSprite = slot.sprites[spriteName];
- slot.currentSpriteName = spriteName;
- }
- }
- slotContainer.visible = true;
-
- var bone = slot.bone;
-
- slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01;
- slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11;
- slotContainer.scale.x = bone.worldScaleX;
- slotContainer.scale.y = bone.worldScaleY;
-
- slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180);
- }
-
- PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
-};
-
-
-PIXI.Spine.prototype.createSprite = function (slot, descriptor) {
- var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png";
- var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name));
- sprite.scale = descriptor.scale;
- sprite.rotation = descriptor.rotation;
- sprite.anchor.x = sprite.anchor.y = 0.5;
-
- slot.sprites = slot.sprites || {};
- slot.sprites[descriptor.name] = sprite;
- return sprite;
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-PIXI.BaseTextureCache = {};
-PIXI.texturesToUpdate = [];
-PIXI.texturesToDestroy = [];
-
-PIXI.BaseTextureCacheIdGenerator = 0;
-
-/**
- * A texture stores the information that represents an image. All textures have a base texture
- *
- * @class BaseTexture
- * @uses EventTarget
- * @constructor
- * @param source {String} the source object (image or canvas)
- * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts
- */
-PIXI.BaseTexture = function(source, scaleMode)
-{
- PIXI.EventTarget.call( this );
-
- /**
- * [read-only] The width of the base texture set when the image has loaded
- *
- * @property width
- * @type Number
- * @readOnly
- */
- this.width = 100;
-
- /**
- * [read-only] The height of the base texture set when the image has loaded
- *
- * @property height
- * @type Number
- * @readOnly
- */
- this.height = 100;
-
- /**
- * The scale mode to apply when scaling this texture
- * @property scaleMode
- * @type PIXI.scaleModes
- * @default PIXI.scaleModes.LINEAR
- */
- this.scaleMode = scaleMode || PIXI.scaleModes.DEFAULT;
-
- /**
- * [read-only] Describes if the base texture has loaded or not
- *
- * @property hasLoaded
- * @type Boolean
- * @readOnly
- */
- this.hasLoaded = false;
-
- /**
- * The source that is loaded to create the texture
- *
- * @property source
- * @type Image
- */
- this.source = source;
-
- if(!source)return;
-
- if(this.source.complete || this.source.getContext)
- {
- 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.imageUrl = null;
- this._powerOf2 = false;
-
- //TODO will be used for futer pixi 1.5...
- this.id = PIXI.BaseTextureCacheIdGenerator++;
-
- // used for webGL
- this._glTextures = [];
-
-};
-
-PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture;
-
-/**
- * Destroys this base texture
- *
- * @method destroy
- */
-PIXI.BaseTexture.prototype.destroy = function()
-{
- if(this.imageUrl)
- {
- delete PIXI.BaseTextureCache[this.imageUrl];
- this.imageUrl = null;
- this.source.src = null;
- }
- this.source = null;
- PIXI.texturesToDestroy.push(this);
-};
-
-/**
- * Changes the source image of the texture
- *
- * @method updateSourceImage
- * @param newSrc {String} the path of the image
- */
-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
- * If the image is not in the base texture cache it will be created and loaded
- *
- * @static
- * @method fromImage
- * @param imageUrl {String} The image url of the texture
- * @param crossorigin {Boolean}
- * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts
- * @return BaseTexture
- */
-PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin, scaleMode)
-{
- var baseTexture = PIXI.BaseTextureCache[imageUrl];
- crossorigin = !crossorigin;
-
- 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;
-};
-
-PIXI.BaseTexture.fromCanvas = function(canvas, scaleMode)
-{
- if(!canvas._pixiId)
- {
- canvas._pixiId = 'canvas_' + PIXI.TextureCacheIdGenerator++;
- }
-
- var baseTexture = PIXI.BaseTextureCache[canvas._pixiId];
-
- if(!baseTexture)
- {
- baseTexture = new PIXI.BaseTexture(canvas, scaleMode);
- PIXI.BaseTextureCache[canvas._pixiId] = baseTexture;
- }
-
- return baseTexture;
-};
-
-
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-PIXI.TextureCache = {};
-PIXI.FrameCache = {};
-
-PIXI.TextureCacheIdGenerator = 0;
-
-/**
- * A texture stores the information that represents an image or part of an image. It cannot be added
- * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used
- *
- * @class Texture
- * @uses EventTarget
- * @constructor
- * @param baseTexture {BaseTexture} The base texture source to create the texture from
- * @param frame {Rectangle} The rectangle frame of the texture to show
- */
-PIXI.Texture = function(baseTexture, frame)
-{
- PIXI.EventTarget.call( this );
-
- if(!frame)
- {
- this.noFrame = true;
- frame = new PIXI.Rectangle(0,0,1,1);
- }
-
- if(baseTexture instanceof PIXI.Texture)
- baseTexture = baseTexture.baseTexture;
-
- /**
- * The base texture of that this texture uses
- *
- * @property baseTexture
- * @type BaseTexture
- */
- this.baseTexture = baseTexture;
-
- /**
- * The frame specifies the region of the base texture that this texture uses
- *
- * @property frame
- * @type Rectangle
- */
- this.frame = frame;
-
- /**
- * The trim point
- *
- * @property trim
- * @type Rectangle
- */
- this.trim = null;
-
- this.scope = this;
-
- 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;
-
-/**
- * Called when the base texture is loaded
- *
- * @method onBaseTextureLoaded
- * @param event
- * @private
- */
-PIXI.Texture.prototype.onBaseTextureLoaded = function()
-{
- var baseTexture = this.baseTexture;
- baseTexture.removeEventListener( 'loaded', this.onLoaded );
-
- 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 } );
-};
-
-/**
- * Destroys this texture
- *
- * @method destroy
- * @param destroyBase {Boolean} Whether to destroy the base texture as well
- */
-PIXI.Texture.prototype.destroy = function(destroyBase)
-{
- if(destroyBase) this.baseTexture.destroy();
-};
-
-/**
- * Specifies the rectangle region of the baseTexture
- *
- * @method setFrame
- * @param frame {Rectangle} The frame of the texture to set it to
- */
-PIXI.Texture.prototype.setFrame = function(frame)
-{
- this.frame = frame;
- this.width = frame.width;
- this.height = frame.height;
-
- if(frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height)
- {
- throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this);
- }
-
- this.updateFrame = true;
-
- PIXI.Texture.frameUpdates.push(this);
-
-
- //this.dispatchEvent( { type: 'update', content: this } );
-};
-
-PIXI.Texture.prototype._updateWebGLuvs = function()
-{
- if(!this._uvs)this._uvs = new PIXI.TextureUvs();
-
- var frame = this.frame;
- var tw = this.baseTexture.width;
- var th = this.baseTexture.height;
-
- this._uvs.x0 = frame.x / tw;
- this._uvs.y0 = frame.y / th;
-
- this._uvs.x1 = (frame.x + frame.width) / tw;
- this._uvs.y1 = frame.y / th;
-
- this._uvs.x2 = (frame.x + frame.width) / tw;
- this._uvs.y2 = (frame.y + frame.height) / th;
-
- this._uvs.x3 = frame.x / tw;
- this._uvs.y3 = (frame.y + frame.height) / th;
-};
-
-/**
- * Helper function that returns a texture based on an image url
- * If the image is not in the texture cache it will be created and loaded
- *
- * @static
- * @method fromImage
- * @param imageUrl {String} The image url of the texture
- * @param crossorigin {Boolean} Whether requests should be treated as crossorigin
- * @return Texture
- */
-PIXI.Texture.fromImage = function(imageUrl, crossorigin, scaleMode)
-{
- 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
- * If the frame id is not in the texture cache an error will be thrown
- *
- * @static
- * @method fromFrame
- * @param frameId {String} The frame id of the texture
- * @return Texture
- */
-PIXI.Texture.fromFrame = function(frameId)
-{
- var texture = PIXI.TextureCache[frameId];
- if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache ');
- return texture;
-};
-
-/**
- * Helper function that returns a texture based on a canvas element
- * If the canvas is not in the texture cache it will be created and loaded
- *
- * @static
- * @method fromCanvas
- * @param canvas {Canvas} The canvas element source of the texture
- * @return Texture
- */
-PIXI.Texture.fromCanvas = function(canvas, scaleMode)
-{
- var baseTexture = PIXI.BaseTexture.fromCanvas(canvas, scaleMode);
-
- return new PIXI.Texture( baseTexture );
-
-};
-
-
-/**
- * Adds a texture to the textureCache.
- *
- * @static
- * @method addTextureToCache
- * @param texture {Texture}
- * @param id {String} the id that the texture will be stored against.
- */
-PIXI.Texture.addTextureToCache = function(texture, id)
-{
- PIXI.TextureCache[id] = texture;
-};
-
-/**
- * Remove a texture from the textureCache.
- *
- * @static
- * @method removeTextureFromCache
- * @param id {String} the id of the texture to be removed
- * @return {Texture} the texture that was removed
- */
-PIXI.Texture.removeTextureFromCache = function(id)
-{
- var texture = PIXI.TextureCache[id];
- PIXI.TextureCache[id] = null;
- return texture;
-};
-
-// this is more for webGL.. it contains updated frames..
-PIXI.Texture.frameUpdates = [];
-
-PIXI.TextureUvs = function()
-{
- this.x0 = 0;
- this.y0 = 0;
-
- this.x1 = 0;
- this.y1 = 0;
-
- this.x2 = 0;
- this.y2 = 0;
-
- this.x3 = 0;
- this.y4 = 0;
-
-
-};
-
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it.
-
- __Hint__: All DisplayObjects (exmpl. Sprites) that render on RenderTexture should be preloaded.
- Otherwise black rectangles will be drawn instead.
-
- RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example:
-
- var renderTexture = new PIXI.RenderTexture(800, 600);
- var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
- sprite.position.x = 800/2;
- sprite.position.y = 600/2;
- sprite.anchor.x = 0.5;
- sprite.anchor.y = 0.5;
- renderTexture.render(sprite);
-
- Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used:
-
- var doc = new PIXI.DisplayObjectContainer();
- doc.addChild(sprite);
- renderTexture.render(doc); // Renders to center of renderTexture
-
- * @class RenderTexture
- * @extends Texture
- * @constructor
- * @param width {Number} The width of the render texture
- * @param height {Number} The height of the render texture
- */
-PIXI.RenderTexture = function(width, height, renderer)
-{
- PIXI.EventTarget.call( this );
-
- /**
- * The with of the render texture
- *
- * @property width
- * @type Number
- */
- this.width = width || 100;
- /**
- * The height of the render texture
- *
- * @property height
- * @type Number
- */
- this.height = height || 100;
-
- /**
- * The framing rectangle of the render texture
- *
- * @property frame
- * @type Rectangle
- */
- this.frame = new PIXI.Rectangle(0, 0, this.width, this.height);
-
- /**
- * The base texture object that this texture uses
- *
- * @property baseTexture
- * @type BaseTexture
- */
- 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;
-
-PIXI.RenderTexture.prototype.resize = function(width, height)
-{
- this.width = width;
- this.height = height;
-
- this.frame.width = this.width;
- this.frame.height = this.height;
-
- if(this.renderer.type === PIXI.WEBGL_RENDERER)
- {
- this.projection.x = this.width / 2;
- this.projection.y = -this.height / 2;
-
- var gl = this.renderer.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);
- }
-
- PIXI.Texture.frameUpdates.push(this);
-};
-
-/**
- * This function will draw the display object to the texture.
- *
- * @method renderWebGL
- * @param displayObject {DisplayObject} The display object to render this texture on
- * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn
- * @private
- */
-PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear)
-{
- //TOOD replace position with matrix..
- var gl = this.renderer.gl;
-
- gl.colorMask(true, true, true, true);
-
- gl.viewport(0, 0, this.width, this.height);
-
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer );
-
- if(clear)this.textureBuffer.clear();
-
- // 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.RenderTexture.tempMatrix;
- // modify to flip...
- displayObject.worldTransform.d = -1;
- displayObject.worldTransform.ty = this.projection.y * -2;
-
- if(position)
- {
- displayObject.worldTransform.tx = position.x;
- displayObject.worldTransform.ty -= position.y;
- }
-
- for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded
- * supported. Supported image formats include 'jpeg', 'jpg', 'png', 'gif'. Supported
- * sprite sheet data formats only include 'JSON' at this time. Supported bitmap font
- * data formats include 'xml' and 'fnt'.
- * @param crossorigin {Boolean} Whether requests should be treated as crossorigin
- */
-PIXI.AssetLoader = function(assetURLs, crossorigin)
-{
- PIXI.EventTarget.call(this);
-
- /**
- * The array of asset URLs that are going to be loaded
- *
- * @property assetURLs
- * @type Array
- */
- this.assetURLs = assetURLs;
-
- /**
- * Whether the requests should be treated as cross origin
- *
- * @property crossorigin
- * @type Boolean
- */
- this.crossorigin = crossorigin;
-
- /**
- * Maps file extension to loader types
- *
- * @property loadersByType
- * @type Object
- */
- this.loadersByType = {
- 'jpg': PIXI.ImageLoader,
- 'jpeg': PIXI.ImageLoader,
- 'png': PIXI.ImageLoader,
- 'gif': PIXI.ImageLoader,
- 'json': PIXI.JsonLoader,
- 'atlas': PIXI.AtlasLoader,
- 'anim': PIXI.SpineLoader,
- 'xml': PIXI.BitmapFontLoader,
- 'fnt': PIXI.BitmapFontLoader
- };
-};
-
-/**
- * Fired when an item has loaded
- * @event onProgress
- */
-
-/**
- * Fired when all the assets have loaded
- * @event onComplete
- */
-
-// constructor
-PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader;
-
-/**
- * Given a filename, returns its extension, wil
- *
- * @method _getDataType
- * @param str {String} the name of the asset
- */
-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
- *
- * @method load
- */
-PIXI.AssetLoader.prototype.load = function()
-{
- var scope = this;
-
- function onLoad(evt) {
- scope.onAssetLoaded(evt.loader);
- }
-
- this.loadCount = this.assetURLs.length;
-
- for (var i=0; i < this.assetURLs.length; i++)
- {
- var fileName = this.assetURLs[i];
- //first see if we have a data URI scheme..
- var fileType = this._getDataType(fileName);
-
- //if not, assume it's a file URI
- if (!fileType)
- fileType = fileName.split('?').shift().split('.').pop().toLowerCase();
-
- var Constructor = this.loadersByType[fileType];
- if(!Constructor)
- throw new Error(fileType + ' is an unsupported file type');
-
- var loader = new Constructor(fileName, this.crossorigin);
-
- loader.addEventListener('loaded', onLoad);
- loader.load();
- }
-};
-
-/**
- * Invoked after each file is loaded
- *
- * @method onAssetLoaded
- * @private
- */
-PIXI.AssetLoader.prototype.onAssetLoaded = function(loader)
-{
- this.loadCount--;
- this.dispatchEvent({ type: 'onProgress', content: this, loader: loader });
- if (this.onProgress) this.onProgress(loader);
-
- if (!this.loadCount)
- {
- this.dispatchEvent({type: 'onComplete', content: this});
- if(this.onComplete) this.onComplete();
- }
-};
-
-/**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
-/**
- * The json file loader is used to load in JSON data and parse it
- * When loaded this class will dispatch a 'loaded' event
- * If loading fails this class will dispatch an 'error' event
- *
- * @class JsonLoader
- * @uses EventTarget
- * @constructor
- * @param url {String} The url of the JSON file
- * @param crossorigin {Boolean} Whether requests should be treated as crossorigin
- */
-PIXI.JsonLoader = function (url, crossorigin) {
- PIXI.EventTarget.call(this);
-
- /**
- * The url of the bitmap font data
- *
- * @property url
- * @type String
- */
- this.url = url;
-
- /**
- * Whether the requests should be treated as cross origin
- *
- * @property crossorigin
- * @type Boolean
- */
- this.crossorigin = crossorigin;
-
- /**
- * [read-only] The base url of the bitmap font data
- *
- * @property baseUrl
- * @type String
- * @readOnly
- */
- this.baseUrl = url.replace(/[^\/]*$/, '');
-
- /**
- * [read-only] Whether the data has loaded yet
- *
- * @property loaded
- * @type Boolean
- * @readOnly
- */
- this.loaded = false;
-
-};
-
-// constructor
-PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader;
-
-/**
- * Loads the JSON data
- *
- * @method load
- */
-PIXI.JsonLoader.prototype.load = function () {
- this.ajaxRequest = new PIXI.AjaxRequest(this.crossorigin);
- var scope = this;
- this.ajaxRequest.onreadystatechange = function () {
- scope.onJSONLoaded();
- };
-
- this.ajaxRequest.open('GET', this.url, true);
- if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType('application/json');
- this.ajaxRequest.send(null);
-};
-
-/**
- * Invoke when JSON file is loaded
- *
- * @method onJSONLoaded
- * @private
- */
-PIXI.JsonLoader.prototype.onJSONLoaded = function () {
- if (this.ajaxRequest.readyState === 4) {
- if (this.ajaxRequest.status === 200 || window.location.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];
-
- var actualSize = frameData[i].sourceSize;
- var realSize = frameData[i].spriteSourceSize;
-
- texture.trim = new PIXI.Rectangle(realSize.x, realSize.y, actualSize.w, 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();
- }
- }
-};
-
-/**
- * Invoke when json file loaded
- *
- * @method onLoaded
- * @private
- */
-PIXI.JsonLoader.prototype.onLoaded = function () {
- this.loaded = true;
- this.dispatchEvent({
- type: 'loaded',
- content: this
- });
-};
-
-/**
- * Invoke when error occured
- *
- * @method onError
- * @private
- */
-PIXI.JsonLoader.prototype.onError = function () {
- this.dispatchEvent({
- type: 'error',
- content: this
- });
-};
-/**
- * @author Martin Kelm http://mkelm.github.com
- */
-
-/**
- * The atlas file loader is used to load in Atlas data and parse it
- * When loaded this class will dispatch a 'loaded' event
- * If loading fails this class will dispatch an '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;
-
-
- /**
- * Starts loading the JSON file
- *
- * @method load
- */
-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
- * @method onAtlasLoaded
- * @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 has loaded
- * @method onLoaded
- * @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
- * @method onError
- * @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 in 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 a 'texture atlas') as it means sprites 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.fromFrameId()
- * This loader will load the image file that the Spritesheet points to as well as the data.
- * When loaded this class will dispatch a 'loaded' event
- *
- * @class SpriteSheetLoader
- * @uses EventTarget
- * @constructor
- * @param url {String} The url of the sprite sheet JSON file
- * @param crossorigin {Boolean} Whether requests should be treated as crossorigin
- */
-PIXI.SpriteSheetLoader = function (url, crossorigin) {
- /*
- * i use texture packer to load the assets..
- * http://www.codeandweb.com/texturepacker
- * make sure to set the format as 'JSON'
- */
- PIXI.EventTarget.call(this);
-
- /**
- * The url of the bitmap font data
- *
- * @property url
- * @type String
- */
- this.url = url;
-
- /**
- * Whether the requests should be treated as cross origin
- *
- * @property crossorigin
- * @type Boolean
- */
- this.crossorigin = crossorigin;
-
- /**
- * [read-only] The base url of the bitmap font data
- *
- * @property baseUrl
- * @type String
- * @readOnly
- */
- this.baseUrl = url.replace(/[^\/]*$/, '');
-
- /**
- * The texture being loaded
- *
- * @property texture
- * @type Texture
- */
- this.texture = null;
-
- /**
- * The frames of the sprite sheet
- *
- * @property frames
- * @type Object
- */
- this.frames = {};
-};
-
-// constructor
-PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader;
-
-/**
- * This will begin loading the JSON file
- *
- * @method load
- */
-PIXI.SpriteSheetLoader.prototype.load = function () {
- var scope = this;
- var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin);
- jsonLoader.addEventListener('loaded', function (event) {
- scope.json = event.content.json;
- scope.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.fromFrameId()
- * 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} width 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= arr.length) {
+ callback();
+ }
+ }
+ }
+ };
+ async.forEach = async.each;
+
+ async.eachSeries = function (arr, iterator, callback) {
+ callback = callback || function () {};
+ if (!arr.length) {
+ return callback();
+ }
+ var completed = 0;
+ var iterate = function () {
+ iterator(arr[completed], function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ if (completed >= arr.length) {
+ callback();
+ }
+ else {
+ iterate();
+ }
+ }
+ });
+ };
+ iterate();
+ };
+ async.forEachSeries = async.eachSeries;
+
+ async.eachLimit = function (arr, limit, iterator, callback) {
+ var fn = _eachLimit(limit);
+ fn.apply(null, [arr, iterator, callback]);
+ };
+ async.forEachLimit = async.eachLimit;
+
+ var _eachLimit = function (limit) {
+
+ return function (arr, iterator, callback) {
+ callback = callback || function () {};
+ if (!arr.length || limit <= 0) {
+ return callback();
+ }
+ var completed = 0;
+ var started = 0;
+ var running = 0;
+
+ (function replenish () {
+ if (completed >= arr.length) {
+ return callback();
+ }
+
+ while (running < limit && started < arr.length) {
+ started += 1;
+ running += 1;
+ iterator(arr[started - 1], function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ running -= 1;
+ if (completed >= arr.length) {
+ callback();
+ }
+ else {
+ replenish();
+ }
+ }
+ });
+ }
+ })();
+ };
+ };
+
+
+ var doParallel = function (fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [async.each].concat(args));
+ };
+ };
+ var doParallelLimit = function(limit, fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [_eachLimit(limit)].concat(args));
+ };
+ };
+ var doSeries = function (fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [async.eachSeries].concat(args));
+ };
+ };
+
+
+ var _asyncMap = function (eachfn, arr, iterator, callback) {
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ if (!callback) {
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (err) {
+ callback(err);
+ });
+ });
+ } else {
+ var results = [];
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (err, v) {
+ results[x.index] = v;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+ };
+ async.map = doParallel(_asyncMap);
+ async.mapSeries = doSeries(_asyncMap);
+ async.mapLimit = function (arr, limit, iterator, callback) {
+ return _mapLimit(limit)(arr, iterator, callback);
+ };
+
+ var _mapLimit = function(limit) {
+ return doParallelLimit(limit, _asyncMap);
+ };
+
+ // reduce only has a series version, as doing reduce in parallel won't
+ // work in many situations.
+ async.reduce = function (arr, memo, iterator, callback) {
+ async.eachSeries(arr, function (x, callback) {
+ iterator(memo, x, function (err, v) {
+ memo = v;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, memo);
+ });
+ };
+ // inject alias
+ async.inject = async.reduce;
+ // foldl alias
+ async.foldl = async.reduce;
+
+ async.reduceRight = function (arr, memo, iterator, callback) {
+ var reversed = _map(arr, function (x) {
+ return x;
+ }).reverse();
+ async.reduce(reversed, memo, iterator, callback);
+ };
+ // foldr alias
+ async.foldr = async.reduceRight;
+
+ var _filter = function (eachfn, arr, iterator, callback) {
+ var results = [];
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (v) {
+ if (v) {
+ results.push(x);
+ }
+ callback();
+ });
+ }, function (err) {
+ callback(_map(results.sort(function (a, b) {
+ return a.index - b.index;
+ }), function (x) {
+ return x.value;
+ }));
+ });
+ };
+ async.filter = doParallel(_filter);
+ async.filterSeries = doSeries(_filter);
+ // select alias
+ async.select = async.filter;
+ async.selectSeries = async.filterSeries;
+
+ var _reject = function (eachfn, arr, iterator, callback) {
+ var results = [];
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (v) {
+ if (!v) {
+ results.push(x);
+ }
+ callback();
+ });
+ }, function (err) {
+ callback(_map(results.sort(function (a, b) {
+ return a.index - b.index;
+ }), function (x) {
+ return x.value;
+ }));
+ });
+ };
+ async.reject = doParallel(_reject);
+ async.rejectSeries = doSeries(_reject);
+
+ var _detect = function (eachfn, arr, iterator, main_callback) {
+ eachfn(arr, function (x, callback) {
+ iterator(x, function (result) {
+ if (result) {
+ main_callback(x);
+ main_callback = function () {};
+ }
+ else {
+ callback();
+ }
+ });
+ }, function (err) {
+ main_callback();
+ });
+ };
+ async.detect = doParallel(_detect);
+ async.detectSeries = doSeries(_detect);
+
+ async.some = function (arr, iterator, main_callback) {
+ async.each(arr, function (x, callback) {
+ iterator(x, function (v) {
+ if (v) {
+ main_callback(true);
+ main_callback = function () {};
+ }
+ callback();
+ });
+ }, function (err) {
+ main_callback(false);
+ });
+ };
+ // any alias
+ async.any = async.some;
+
+ async.every = function (arr, iterator, main_callback) {
+ async.each(arr, function (x, callback) {
+ iterator(x, function (v) {
+ if (!v) {
+ main_callback(false);
+ main_callback = function () {};
+ }
+ callback();
+ });
+ }, function (err) {
+ main_callback(true);
+ });
+ };
+ // all alias
+ async.all = async.every;
+
+ async.sortBy = function (arr, iterator, callback) {
+ async.map(arr, function (x, callback) {
+ iterator(x, function (err, criteria) {
+ if (err) {
+ callback(err);
+ }
+ else {
+ callback(null, {value: x, criteria: criteria});
+ }
+ });
+ }, function (err, results) {
+ if (err) {
+ return callback(err);
+ }
+ else {
+ var fn = function (left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ };
+ callback(null, _map(results.sort(fn), function (x) {
+ return x.value;
+ }));
+ }
+ });
+ };
+
+ async.auto = function (tasks, callback) {
+ callback = callback || function () {};
+ var keys = _keys(tasks);
+ var remainingTasks = keys.length
+ if (!remainingTasks) {
+ return callback();
+ }
+
+ var results = {};
+
+ var listeners = [];
+ var addListener = function (fn) {
+ listeners.unshift(fn);
+ };
+ var removeListener = function (fn) {
+ for (var i = 0; i < listeners.length; i += 1) {
+ if (listeners[i] === fn) {
+ listeners.splice(i, 1);
+ return;
+ }
+ }
+ };
+ var taskComplete = function () {
+ remainingTasks--
+ _each(listeners.slice(0), function (fn) {
+ fn();
+ });
+ };
+
+ addListener(function () {
+ if (!remainingTasks) {
+ var theCallback = callback;
+ // prevent final callback from calling itself if it errors
+ callback = function () {};
+
+ theCallback(null, results);
+ }
+ });
+
+ _each(keys, function (k) {
+ var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
+ var taskCallback = function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ if (err) {
+ var safeResults = {};
+ _each(_keys(results), function(rkey) {
+ safeResults[rkey] = results[rkey];
+ });
+ safeResults[k] = args;
+ callback(err, safeResults);
+ // stop subsequent errors hitting callback multiple times
+ callback = function () {};
+ }
+ else {
+ results[k] = args;
+ async.setImmediate(taskComplete);
+ }
+ };
+ var requires = task.slice(0, Math.abs(task.length - 1)) || [];
+ var ready = function () {
+ return _reduce(requires, function (a, x) {
+ return (a && results.hasOwnProperty(x));
+ }, true) && !results.hasOwnProperty(k);
+ };
+ if (ready()) {
+ task[task.length - 1](taskCallback, results);
+ }
+ else {
+ var listener = function () {
+ if (ready()) {
+ removeListener(listener);
+ task[task.length - 1](taskCallback, results);
+ }
+ };
+ addListener(listener);
+ }
+ });
+ };
+
+ async.retry = function(times, task, callback) {
+ var DEFAULT_TIMES = 5;
+ var attempts = [];
+ // Use defaults if times not passed
+ if (typeof times === 'function') {
+ callback = task;
+ task = times;
+ times = DEFAULT_TIMES;
+ }
+ // Make sure times is a number
+ times = parseInt(times, 10) || DEFAULT_TIMES;
+ var wrappedTask = function(wrappedCallback, wrappedResults) {
+ var retryAttempt = function(task, finalAttempt) {
+ return function(seriesCallback) {
+ task(function(err, result){
+ seriesCallback(!err || finalAttempt, {err: err, result: result});
+ }, wrappedResults);
+ };
+ };
+ while (times) {
+ attempts.push(retryAttempt(task, !(times-=1)));
+ }
+ async.series(attempts, function(done, data){
+ data = data[data.length - 1];
+ (wrappedCallback || callback)(data.err, data.result);
+ });
+ }
+ // If a callback is passed, run this as a controll flow
+ return callback ? wrappedTask() : wrappedTask
+ };
+
+ async.waterfall = function (tasks, callback) {
+ callback = callback || function () {};
+ if (!_isArray(tasks)) {
+ var err = new Error('First argument to waterfall must be an array of functions');
+ return callback(err);
+ }
+ if (!tasks.length) {
+ return callback();
+ }
+ var wrapIterator = function (iterator) {
+ return function (err) {
+ if (err) {
+ callback.apply(null, arguments);
+ callback = function () {};
+ }
+ else {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var next = iterator.next();
+ if (next) {
+ args.push(wrapIterator(next));
+ }
+ else {
+ args.push(callback);
+ }
+ async.setImmediate(function () {
+ iterator.apply(null, args);
+ });
+ }
+ };
+ };
+ wrapIterator(async.iterator(tasks))();
+ };
+
+ var _parallel = function(eachfn, tasks, callback) {
+ callback = callback || function () {};
+ if (_isArray(tasks)) {
+ eachfn.map(tasks, function (fn, callback) {
+ if (fn) {
+ fn(function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ callback.call(null, err, args);
+ });
+ }
+ }, callback);
+ }
+ else {
+ var results = {};
+ eachfn.each(_keys(tasks), function (k, callback) {
+ tasks[k](function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ results[k] = args;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+ };
+
+ async.parallel = function (tasks, callback) {
+ _parallel({ map: async.map, each: async.each }, tasks, callback);
+ };
+
+ async.parallelLimit = function(tasks, limit, callback) {
+ _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
+ };
+
+ async.series = function (tasks, callback) {
+ callback = callback || function () {};
+ if (_isArray(tasks)) {
+ async.mapSeries(tasks, function (fn, callback) {
+ if (fn) {
+ fn(function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ callback.call(null, err, args);
+ });
+ }
+ }, callback);
+ }
+ else {
+ var results = {};
+ async.eachSeries(_keys(tasks), function (k, callback) {
+ tasks[k](function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ results[k] = args;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+ };
+
+ async.iterator = function (tasks) {
+ var makeCallback = function (index) {
+ var fn = function () {
+ if (tasks.length) {
+ tasks[index].apply(null, arguments);
+ }
+ return fn.next();
+ };
+ fn.next = function () {
+ return (index < tasks.length - 1) ? makeCallback(index + 1): null;
+ };
+ return fn;
+ };
+ return makeCallback(0);
+ };
+
+ async.apply = function (fn) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function () {
+ return fn.apply(
+ null, args.concat(Array.prototype.slice.call(arguments))
+ );
+ };
+ };
+
+ var _concat = function (eachfn, arr, fn, callback) {
+ var r = [];
+ eachfn(arr, function (x, cb) {
+ fn(x, function (err, y) {
+ r = r.concat(y || []);
+ cb(err);
+ });
+ }, function (err) {
+ callback(err, r);
+ });
+ };
+ async.concat = doParallel(_concat);
+ async.concatSeries = doSeries(_concat);
+
+ async.whilst = function (test, iterator, callback) {
+ if (test()) {
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ async.whilst(test, iterator, callback);
+ });
+ }
+ else {
+ callback();
+ }
+ };
+
+ async.doWhilst = function (iterator, test, callback) {
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (test.apply(null, args)) {
+ async.doWhilst(iterator, test, callback);
+ }
+ else {
+ callback();
+ }
+ });
+ };
+
+ async.until = function (test, iterator, callback) {
+ if (!test()) {
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ async.until(test, iterator, callback);
+ });
+ }
+ else {
+ callback();
+ }
+ };
+
+ async.doUntil = function (iterator, test, callback) {
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (!test.apply(null, args)) {
+ async.doUntil(iterator, test, callback);
+ }
+ else {
+ callback();
+ }
+ });
+ };
+
+ async.queue = function (worker, concurrency) {
+ if (concurrency === undefined) {
+ concurrency = 1;
+ }
+ function _insert(q, data, pos, callback) {
+ if (!q.started){
+ q.started = true;
+ }
+ if (!_isArray(data)) {
+ data = [data];
+ }
+ if(data.length == 0) {
+ // call drain immediately if there are no tasks
+ return async.setImmediate(function() {
+ if (q.drain) {
+ q.drain();
+ }
+ });
+ }
+ _each(data, function(task) {
+ var item = {
+ data: task,
+ callback: typeof callback === 'function' ? callback : null
+ };
+
+ if (pos) {
+ q.tasks.unshift(item);
+ } else {
+ q.tasks.push(item);
+ }
+
+ if (q.saturated && q.tasks.length === q.concurrency) {
+ q.saturated();
+ }
+ async.setImmediate(q.process);
+ });
+ }
+
+ var workers = 0;
+ var q = {
+ tasks: [],
+ concurrency: concurrency,
+ saturated: null,
+ empty: null,
+ drain: null,
+ started: false,
+ paused: false,
+ push: function (data, callback) {
+ _insert(q, data, false, callback);
+ },
+ kill: function () {
+ q.drain = null;
+ q.tasks = [];
+ },
+ unshift: function (data, callback) {
+ _insert(q, data, true, callback);
+ },
+ process: function () {
+ if (!q.paused && workers < q.concurrency && q.tasks.length) {
+ var task = q.tasks.shift();
+ if (q.empty && q.tasks.length === 0) {
+ q.empty();
+ }
+ workers += 1;
+ var next = function () {
+ workers -= 1;
+ if (task.callback) {
+ task.callback.apply(task, arguments);
+ }
+ if (q.drain && q.tasks.length + workers === 0) {
+ q.drain();
+ }
+ q.process();
+ };
+ var cb = only_once(next);
+ worker(task.data, cb);
+ }
+ },
+ length: function () {
+ return q.tasks.length;
+ },
+ running: function () {
+ return workers;
+ },
+ idle: function() {
+ return q.tasks.length + workers === 0;
+ },
+ pause: function () {
+ if (q.paused === true) { return; }
+ q.paused = true;
+ q.process();
+ },
+ resume: function () {
+ if (q.paused === false) { return; }
+ q.paused = false;
+ q.process();
+ }
+ };
+ return q;
+ };
+
+ async.priorityQueue = function (worker, concurrency) {
+
+ function _compareTasks(a, b){
+ return a.priority - b.priority;
+ };
+
+ function _binarySearch(sequence, item, compare) {
+ var beg = -1,
+ end = sequence.length - 1;
+ while (beg < end) {
+ var mid = beg + ((end - beg + 1) >>> 1);
+ if (compare(item, sequence[mid]) >= 0) {
+ beg = mid;
+ } else {
+ end = mid - 1;
+ }
+ }
+ return beg;
+ }
+
+ function _insert(q, data, priority, callback) {
+ if (!q.started){
+ q.started = true;
+ }
+ if (!_isArray(data)) {
+ data = [data];
+ }
+ if(data.length == 0) {
+ // call drain immediately if there are no tasks
+ return async.setImmediate(function() {
+ if (q.drain) {
+ q.drain();
+ }
+ });
+ }
+ _each(data, function(task) {
+ var item = {
+ data: task,
+ priority: priority,
+ callback: typeof callback === 'function' ? callback : null
+ };
+
+ q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
+
+ if (q.saturated && q.tasks.length === q.concurrency) {
+ q.saturated();
+ }
+ async.setImmediate(q.process);
+ });
+ }
+
+ // Start with a normal queue
+ var q = async.queue(worker, concurrency);
+
+ // Override push to accept second parameter representing priority
+ q.push = function (data, priority, callback) {
+ _insert(q, data, priority, callback);
+ };
+
+ // Remove unshift function
+ delete q.unshift;
+
+ return q;
+ };
+
+ async.cargo = function (worker, payload) {
+ var working = false,
+ tasks = [];
+
+ var cargo = {
+ tasks: tasks,
+ payload: payload,
+ saturated: null,
+ empty: null,
+ drain: null,
+ drained: true,
+ push: function (data, callback) {
+ if (!_isArray(data)) {
+ data = [data];
+ }
+ _each(data, function(task) {
+ tasks.push({
+ data: task,
+ callback: typeof callback === 'function' ? callback : null
+ });
+ cargo.drained = false;
+ if (cargo.saturated && tasks.length === payload) {
+ cargo.saturated();
+ }
+ });
+ async.setImmediate(cargo.process);
+ },
+ process: function process() {
+ if (working) return;
+ if (tasks.length === 0) {
+ if(cargo.drain && !cargo.drained) cargo.drain();
+ cargo.drained = true;
+ return;
+ }
+
+ var ts = typeof payload === 'number'
+ ? tasks.splice(0, payload)
+ : tasks.splice(0, tasks.length);
+
+ var ds = _map(ts, function (task) {
+ return task.data;
+ });
+
+ if(cargo.empty) cargo.empty();
+ working = true;
+ worker(ds, function () {
+ working = false;
+
+ var args = arguments;
+ _each(ts, function (data) {
+ if (data.callback) {
+ data.callback.apply(null, args);
+ }
+ });
+
+ process();
+ });
+ },
+ length: function () {
+ return tasks.length;
+ },
+ running: function () {
+ return working;
+ }
+ };
+ return cargo;
+ };
+
+ var _console_fn = function (name) {
+ return function (fn) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ fn.apply(null, args.concat([function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (typeof console !== 'undefined') {
+ if (err) {
+ if (console.error) {
+ console.error(err);
+ }
+ }
+ else if (console[name]) {
+ _each(args, function (x) {
+ console[name](x);
+ });
+ }
+ }
+ }]));
+ };
+ };
+ async.log = _console_fn('log');
+ async.dir = _console_fn('dir');
+ /*async.info = _console_fn('info');
+ async.warn = _console_fn('warn');
+ async.error = _console_fn('error');*/
+
+ async.memoize = function (fn, hasher) {
+ var memo = {};
+ var queues = {};
+ hasher = hasher || function (x) {
+ return x;
+ };
+ var memoized = function () {
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ var key = hasher.apply(null, args);
+ if (key in memo) {
+ async.nextTick(function () {
+ callback.apply(null, memo[key]);
+ });
+ }
+ else if (key in queues) {
+ queues[key].push(callback);
+ }
+ else {
+ queues[key] = [callback];
+ fn.apply(null, args.concat([function () {
+ memo[key] = arguments;
+ var q = queues[key];
+ delete queues[key];
+ for (var i = 0, l = q.length; i < l; i++) {
+ q[i].apply(null, arguments);
+ }
+ }]));
+ }
+ };
+ memoized.memo = memo;
+ memoized.unmemoized = fn;
+ return memoized;
+ };
+
+ async.unmemoize = function (fn) {
+ return function () {
+ return (fn.unmemoized || fn).apply(null, arguments);
+ };
+ };
+
+ async.times = function (count, iterator, callback) {
+ var counter = [];
+ for (var i = 0; i < count; i++) {
+ counter.push(i);
+ }
+ return async.map(counter, iterator, callback);
+ };
+
+ async.timesSeries = function (count, iterator, callback) {
+ var counter = [];
+ for (var i = 0; i < count; i++) {
+ counter.push(i);
+ }
+ return async.mapSeries(counter, iterator, callback);
+ };
+
+ async.seq = function (/* functions... */) {
+ var fns = arguments;
+ return function () {
+ var that = this;
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ async.reduce(fns, args, function (newargs, fn, cb) {
+ fn.apply(that, newargs.concat([function () {
+ var err = arguments[0];
+ var nextargs = Array.prototype.slice.call(arguments, 1);
+ cb(err, nextargs);
+ }]))
+ },
+ function (err, results) {
+ callback.apply(that, [err].concat(results));
+ });
+ };
+ };
+
+ async.compose = function (/* functions... */) {
+ return async.seq.apply(null, Array.prototype.reverse.call(arguments));
+ };
+
+ var _applyEach = function (eachfn, fns /*args...*/) {
+ var go = function () {
+ var that = this;
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ return eachfn(fns, function (fn, cb) {
+ fn.apply(that, args.concat([cb]));
+ },
+ callback);
+ };
+ if (arguments.length > 2) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return go.apply(this, args);
+ }
+ else {
+ return go;
+ }
+ };
+ async.applyEach = doParallel(_applyEach);
+ async.applyEachSeries = doSeries(_applyEach);
+
+ async.forever = function (fn, callback) {
+ function next(err) {
+ if (err) {
+ if (callback) {
+ return callback(err);
+ }
+ throw err;
+ }
+ fn(next);
+ }
+ next();
+ };
+
+ // Node.js
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = async;
+ }
+ // AMD / RequireJS
+ else if (typeof define !== 'undefined' && define.amd) {
+ define([], function () {
+ return async;
+ });
+ }
+ // included directly via