/build/custom/phaser-arcade-physics.js
JavaScript | 17639 lines | 8119 code | 3354 blank | 6166 comment | 1201 complexity | 3d0643572fac43e8b7e174e36a9f2ebf MD5 | raw file
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- *
- * @overview
- *
- * Phaser - http://phaser.io
- *
- * v2.0.3 "Allorallen" - Built: Fri Apr 11 2014 13:08:30
- *
- * By Richard Davey http://www.photonstorm.com @photonstorm
- *
- * Phaser is a fun, free and fast 2D game framework for making HTML5 games
- * for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
- *
- * Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
- * Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
- * Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
- *
- * Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser
- * and my love of framework development originate.
- *
- * Follow development at http://phaser.io and on our forum
- *
- * "If you want your children to be intelligent, read them fairy tales."
- * "If you want them to be more intelligent, read them more fairy tales."
- * -- Albert Einstein
- */
- /**
- * @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.2";
- // 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 <adrien.brault@gmail.com>
- */
- /**
- * @class Polygon
- * @constructor
- * @param points* {Array<Point>|Array<Number>|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<this.points.length; i++) {
- points.push(this.points[i].clone());
- }
- return new PIXI.Polygon(points);
- };
- /**
- * Checks whether the x and y coordinates passed to this function are contained within this polygon
- *
- * @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.Polygon.prototype.contains = function(x, y)
- {
- var inside = false;
- // use some raycasting to test hits
- // https://github.com/substack/point-in-polygon/blob/master/index.js
- for(var i = 0, j = this.points.length - 1; i < this.points.length; j = i++) {
- var xi = this.points[i].x, yi = this.points[i].y,
- xj = this.points[j].x, yj = this.points[j].y,
- intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
- if(intersect) inside = !inside;
- }
- return inside;
- };
- // constructor
- PIXI.Polygon.prototype.constructor = PIXI.Polygon;
- /**
- * @author Chad Engler <chad@pantherdev.com>
- */
- /**
- * 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 <chad@pantherdev.com>
- */
- /**
- * 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 like the hitArea this is used as more of an optimisation
- * rather than figuring out the dimensions of the displayObject each frame you can set this rectangle
- *
- * @property filterArea
- * @type Rectangle
- */
- this.filterArea = null;//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;
- this._cacheAsBitmap = false;
- this._cacheIsDirty = false;
- /*
- * 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;
- }
- });
- /**
- * Set weather or not a the display objects is cached as a bitmap.
- * This basically takes a snap shot of the display object as it is at that moment. It can provide a performance benefit for complex static displayObjects
- * To remove filters simply set this property to 'null'
- * @property cacheAsBitmap
- * @type Boolean
- */
- Object.defineProperty(PIXI.DisplayObject.prototype, 'cacheAsBitmap', {
- get: function() {
- return this._cacheAsBitmap;
- },
- set: function(value) {
- if(this._cacheAsBitmap === value)return;
- if(value)
- {
- //this._cacheIsDirty = true;
- this._generateCachedSprite();
- }
- else
- {
- this._destroyCachedSprite();
- }
- this._cacheAsBitmap = 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()
- {
- 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;
- };
- PIXI.DisplayObject.prototype.generateTexture = function(renderer)
- {
- var bounds = this.getLocalBounds();
- var renderTexture = new PIXI.RenderTexture(bounds.width | 0, bounds.height | 0, renderer);
- renderTexture.render(this);
- return renderTexture;
- };
- PIXI.DisplayObject.prototype.updateCache = function()
- {
- this._generateCachedSprite();
- };
- PIXI.DisplayObject.prototype._renderCachedSprite = function(renderSession)
- {
- if(renderSession.gl)
- {
- PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession);
- }
- else
- {
- PIXI.Sprite.prototype._renderCanvas.call(this._cachedSprite, renderSession);
- }
- };
- PIXI.DisplayObject.prototype._generateCachedSprite = function()//renderSession)
- {
- this._cacheAsBitmap = false;
- var bounds = this.getLocalBounds();
-
- if(!this._cachedSprite)
- {
- var renderTexture = new PIXI.RenderTexture(bounds.width | 0, bounds.height | 0);//, renderSession.renderer);
-
- this._cachedSprite = new PIXI.Sprite(renderTexture);
- this._cachedSprite.worldTransform = this.worldTransform;
- }
- else
- {
- this._cachedSprite.texture.resize(bounds.width | 0, bounds.height | 0);
- }
- //REMOVE filter!
- var tempFilters = this._filters;
- this._filters = null;
- this._cachedSprite.filters = tempFilters;
- this._cachedSprite.texture.render(this);
- this._filters = tempFilters;
- this._cacheAsBitmap = true;
- };
- /**
- * Renders the object using the WebGL renderer
- *
- * @method _renderWebGL
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.DisplayObject.prototype._destroyCachedSprite = function()
- {
- if(!this._cachedSprite)return;
- this._cachedSprite.texture.destroy(true);
- // console.log("DESTROY")
- // let the gc collect the unused sprite
- // TODO could be object pooled!
- this._cachedSprite = null;
- };
- 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<DisplayObject>
- * @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('Supplied index does not exist in the child list, or the supplied DisplayObject must be a child of the caller');
- }
- };
- /**
- * Removes a child from the container.
- *
- * @method removeChild
- * @param child {DisplayObject} The DisplayObject to remove
- */
- PIXI.DisplayObjectContainer.prototype.removeChild = function(child)
- {
- return this.removeChildAt( this.children.indexOf( child ) );
- };
- /**
- * Removes a child from the specified index position in the child list of the container.
- *
- * @method removeChildAt
- * @param index {Number} The index to get the child from
- */
- PIXI.DisplayObjectContainer.prototype.removeChildAt = function(index)
- {
- var child = this.getChildAt( index );
- if(this.stage)
- child.removeStageReference();
- child.parent = undefined;
- this.children.splice( index, 1 );
- return child;
- };
- /**
- * Removes all child instances from the child list of the container.
- *
- * @method removeChildren
- * @param beginIndex {Number} The beginning position. Predefined value is 0.
- * @param endIndex {Number} The ending position. Predefined value is children's array length.
- */
- PIXI.DisplayObjectContainer.prototype.removeChildren = function(beginIndex, endIndex)
- {
- var begin = beginIndex || 0;
- var end = typeof endIndex === 'number' ? endIndex : this.children.length;
- var range = end - begin;
- if (range > 0 && range <= end)
- {
- var removed = this.children.splice(begin, range);
- for (var i = 0; i < removed.length; i++) {
- var child = removed[i];
- if(this.stage)
- child.removeStageReference();
- child.parent = undefined;
- }
- return removed;
- }
- else
- {
- throw new Error( 'Range Error, numeric values are outside the acceptable range' );
- }
- };
- /*
- * 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 );
- if(this._cacheAsBitmap)return;
- for(var i=0,j=this.children.length; i<j; i++)
- {
- this.children[i].updateTransform();
- }
- };
- /**
- * Retrieves the bounds of the displayObjectContainer as a rectangle object
- *
- * @method getBounds
- * @return {Rectangle} the rectangular bounding area
- */
- PIXI.DisplayObjectContainer.prototype.getBounds = function(matrix)
- {
- if(this.children.length === 0)return PIXI.EmptyRectangle;
- // TODO the bounds have already been calculated this render session so return what we have
- if(matrix)
- {
- var matrixCache = this.worldTransform;
- this.worldTransform = matrix;
- this.updateTransform();
- this.worldTransform = matrixCache;
- }
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- var childBounds;
- var childMaxX;
- var childMaxY;
- var childVisible = false;
- for(var i=0,j=this.children.length; i<j; i++)
- {
- var child = this.children[i];
-
- if(!child.visible)continue;
- childVisible = true;
- childBounds = this.children[i].getBounds( matrix );
-
- minX = minX < childBounds.x ? minX : childBounds.x;
- minY = minY < childBounds.y ? minY : childBounds.y;
- childMaxX = childBounds.width + childBounds.x;
- childMaxY = childBounds.height + childBounds.y;
- maxX = maxX > 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<j; i++)
- {
- this.children[i].updateTransform();
- }
- var bounds = this.getBounds();
- this.worldTransform = matrixCache;
- return bounds;
- };
- /**
- * Sets the container's stage reference, the stage this object is connected to
- *
- * @method setStageReference
- * @param stage {Stage} the stage that the container will have as its current stage reference
- */
- PIXI.DisplayObjectContainer.prototype.setStageReference = function(stage)
- {
- this.stage = stage;
- if(this._interactive)this.stage.dirty = true;
- for(var i=0,j=this.children.length; i<j; i++)
- {
- var child = this.children[i];
- child.setStageReference(stage);
- }
- };
- /**
- * removes the current stage reference of the container
- *
- * @method removeStageReference
- */
- PIXI.DisplayObjectContainer.prototype.removeStageReference = function()
- {
- for(var i=0,j=this.children.length; i<j; i++)
- {
- var child = this.children[i];
- child.removeStageReference();
- }
- if(this._interactive)this.stage.dirty = true;
-
- this.stage = null;
- };
- /**
- * Renders the object using the WebGL renderer
- *
- * @method _renderWebGL
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.DisplayObjectContainer.prototype._renderWebGL = function(renderSession)
- {
- if(!this.visible || this.alpha <= 0)return;
-
- if(this._cacheAsBitmap)
- {
- this._renderCachedSprite(renderSession);
- 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);
- }
- // simple render children!
- for(i=0,j=this.children.length; i<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- renderSession.spriteBatch.stop();
- if(this._filters)renderSession.filterManager.popFilter();
- if(this._mask)renderSession.maskManager.popMask(renderSession);
-
- renderSession.spriteBatch.start();
- }
- else
- {
- // simple render children!
- for(i=0,j=this.children.length; i<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- }
- };
- /**
- * Renders the object using the Canvas renderer
- *
- * @method _renderCanvas
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.DisplayObjectContainer.prototype._renderCanvas = function(renderSession)
- {
- if(this.visible === false || this.alpha === 0)return;
- if(this._cacheAsBitmap)
- {
- this._renderCachedSprite(renderSession);
- return;
- }
- if(this._mask)
- {
- renderSession.maskManager.pushMask(this._mask, renderSession.context);
- }
- for(var i=0,j=this.children.length; i<j; i++)
- {
- var child = this.children[i];
- child._renderCanvas(renderSession);
- }
- if(this._mask)
- {
- renderSession.maskManager.popMask(renderSession.context);
- }
- };
- /**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
- /**
- * The Sprite object is the base for all textured objects that are rendered to the screen
- *
- * @class Sprite
- * @extends DisplayObjectContainer
- * @constructor
- * @param texture {Texture} The texture for this sprite
- *
- * A sprite can be created directly from an image like this :
- * var sprite = nex PIXI.Sprite.FromImage('assets/image.png');
- * yourStage.addChild(sprite);
- * then obviously don't forget to add it to the stage you have already created
- */
- PIXI.Sprite = function(texture)
- {
- PIXI.DisplayObjectContainer.call( this );
- /**
- * The anchor sets the origin point of the texture.
- * The default is 0,0 this means the texture's origin is the top left
- * Setting than anchor to 0.5,0.5 means the textures origin is centred
- * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner
- *
- * @property anchor
- * @type Point
- */
- this.anchor = new PIXI.Point();
- /**
- * The texture that the sprite is using
- *
- * @property texture
- * @type Texture
- */
- this.texture = texture;
- /**
- * The width of the sprite (this is initially set by the texture)
- *
- * @property _width
- * @type Number
- * @private
- */
- this._width = 0;
- /**
- * The height of the sprite (this is initially set by the texture)
- *
- * @property _height
- * @type Number
- * @private
- */
- this._height = 0;
- /**
- * The tint applied to the sprite. This is a hex value
- *
- * @property tint
- * @type Number
- * @default 0xFFFFFF
- */
- this.tint = 0xFFFFFF;// * Math.random();
-
- /**
- * The blend mode to be applied to the sprite
- *
- * @property blendMode
- * @type Number
- * @default PIXI.blendModes.NORMAL;
- */
- this.blendMode = PIXI.blendModes.NORMAL;
- if(texture.baseTexture.hasLoaded)
- {
- this.onTextureUpdate();
- }
- else
- {
- this.onTextureUpdateBind = this.onTextureUpdate.bind(this);
- this.texture.addEventListener( 'update', this.onTextureUpdateBind );
- }
- this.renderable = true;
- };
- // constructor
- PIXI.Sprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
- PIXI.Sprite.prototype.constructor = PIXI.Sprite;
- /**
- * The width of the sprite, setting this will actually modify the scale to achieve the value set
- *
- * @property width
- * @type Number
- */
- Object.defineProperty(PIXI.Sprite.prototype, 'width', {
- get: function() {
- return this.scale.x * this.texture.frame.width;
- },
- set: function(value) {
- this.scale.x = value / this.texture.frame.width;
- this._width = value;
- }
- });
- /**
- * The height of the sprite, setting this will actually modify the scale to achieve the value set
- *
- * @property height
- * @type Number
- */
- Object.defineProperty(PIXI.Sprite.prototype, 'height', {
- get: function() {
- return this.scale.y * this.texture.frame.height;
- },
- set: function(value) {
- this.scale.y = value / this.texture.frame.height;
- this._height = value;
- }
- });
- /**
- * Sets the texture of the sprite
- *
- * @method setTexture
- * @param texture {Texture} The PIXI texture that is displayed by the sprite
- */
- PIXI.Sprite.prototype.setTexture = function(texture)
- {
- // stop current texture;
- if(this.texture.baseTexture !== texture.baseTexture)
- {
- this.textureChange = true;
- this.texture = texture;
- }
- else
- {
- this.texture = texture;
- }
- this.cachedTint = 0xFFFFFF;
- this.updateFrame = true;
- };
- /**
- * When the texture is updated, this event will fire to update the scale and frame
- *
- * @method onTextureUpdate
- * @param event
- * @private
- */
- PIXI.Sprite.prototype.onTextureUpdate = function()
- {
- // so if _width is 0 then width was not set..
- if(this._width)this.scale.x = this._width / this.texture.frame.width;
- if(this._height)this.scale.y = this._height / this.texture.frame.height;
- this.updateFrame = true;
- };
- /**
- * Returns the framing rectangle of the sprite as a PIXI.Rectangle object
- *
- * @method getBounds
- * @param matrix {Matrix} the transformation matrix of the sprite
- * @return {Rectangle} the framing rectangle
- */
- PIXI.Sprite.prototype.getBounds = function(matrix)
- {
- var width = this.texture.frame.width;
- var height = this.texture.frame.height;
- var w0 = width * (1-this.anchor.x);
- var w1 = width * -this.anchor.x;
- var h0 = height * (1-this.anchor.y);
- var h1 = height * -this.anchor.y;
- var worldTransform = matrix || this.worldTransform ;
- var a = worldTransform.a;
- var b = worldTransform.c;
- var c = worldTransform.b;
- var d = worldTransform.d;
- var tx = worldTransform.tx;
- var ty = worldTransform.ty;
- var x1 = a * w1 + c * h1 + tx;
- var y1 = d * h1 + b * w1 + ty;
- var x2 = a * w0 + c * h1 + tx;
- var y2 = d * h1 + b * w0 + ty;
- var x3 = a * w0 + c * h0 + tx;
- var y3 = d * h0 + b * w0 + ty;
- var x4 = a * w1 + c * h0 + tx;
- var y4 = d * h0 + b * w1 + ty;
- var maxX = -Infinity;
- var maxY = -Infinity;
- var minX = Infinity;
- var minY = Infinity;
- minX = x1 < minX ? x1 : minX;
- minX = x2 < minX ? x2 : minX;
- minX = x3 < minX ? x3 : minX;
- minX = x4 < minX ? x4 : minX;
- minY = y1 < minY ? y1 : minY;
- minY = y2 < minY ? y2 : minY;
- minY = y3 < minY ? y3 : minY;
- minY = y4 < minY ? y4 : minY;
- maxX = x1 > maxX ? x1 : maxX;
- maxX = x2 > maxX ? x2 : maxX;
- maxX = x3 > maxX ? x3 : maxX;
- maxX = x4 > maxX ? x4 : maxX;
- maxY = y1 > maxY ? y1 : maxY;
- maxY = y2 > maxY ? y2 : maxY;
- maxY = y3 > maxY ? y3 : maxY;
- maxY = y4 > maxY ? y4 : maxY;
- 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<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- // time to stop the sprite batch as either a mask element or a filter draw will happen next
- spriteBatch.stop();
- if(this._filters)renderSession.filterManager.popFilter();
- if(this._mask)renderSession.maskManager.popMask(renderSession);
-
- spriteBatch.start();
- }
- else
- {
- renderSession.spriteBatch.render(this);
- // simple render children!
- for(i=0,j=this.children.length; i<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- }
-
- //TODO check culling
- };
- /**
- * Renders the object using the Canvas renderer
- *
- * @method _renderCanvas
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.Sprite.prototype._renderCanvas = function(renderSession)
- {
- // if the sprite is not visible or the alpha is 0 then no need to render this element
- if(this.visible === false || this.alpha === 0)return;
-
- var frame = this.texture.frame;
- var context = renderSession.context;
- var texture = this.texture;
- if(this.blendMode !== renderSession.currentBlendMode)
- {
- renderSession.currentBlendMode = this.blendMode;
- context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
- }
- if(this._mask)
- {
- renderSession.maskManager.pushMask(this._mask, renderSession.context);
- }
-
- //ignore null sources
- if(frame && frame.width && frame.height && texture.baseTexture.source)
- {
- context.globalAlpha = this.worldAlpha;
- var transform = this.worldTransform;
- // allow for trimming
- if (renderSession.roundPixels)
- {
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0);
- }
- else
- {
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
- }
- //if smoothingEnabled is supported and we need to change the smoothing property for this texture
- if(renderSession.smoothProperty && renderSession.scaleMode !== this.texture.baseTexture.scaleMode) {
- renderSession.scaleMode = this.texture.baseTexture.scaleMode;
- context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR);
- }
- if(this.tint !== 0xFFFFFF)
- {
-
- if(this.cachedTint !== this.tint)
- {
- // no point tinting an image that has not loaded yet!
- if(!texture.baseTexture.hasLoaded)return;
- this.cachedTint = this.tint;
-
- //TODO clean up caching - how to clean up the caches?
- this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
-
- }
- context.drawImage(this.tintedTexture,
- 0,
- 0,
- frame.width,
- frame.height,
- (this.anchor.x) * -frame.width,
- (this.anchor.y) * -frame.height,
- frame.width,
- frame.height);
- }
- else
- {
-
- if(texture.trim)
- {
- var trim = texture.trim;
- context.drawImage(this.texture.baseTexture.source,
- frame.x,
- frame.y,
- frame.width,
- frame.height,
- trim.x - this.anchor.x * trim.width,
- trim.y - this.anchor.y * trim.height,
- frame.width,
- frame.height);
- }
- else
- {
-
- context.drawImage(this.texture.baseTexture.source,
- frame.x,
- frame.y,
- frame.width,
- frame.height,
- (this.anchor.x) * -frame.width,
- (this.anchor.y) * -frame.height,
- frame.width,
- frame.height);
- }
-
- }
- }
- // OVERWRITE
- for(var i=0,j=this.children.length; i<j; i++)
- {
- var child = this.children[i];
- child._renderCanvas(renderSession);
- }
- if(this._mask)
- {
- renderSession.maskManager.popMask(renderSession.context);
- }
- };
- // some helper functions..
- /**
- *
- * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
- * The frame ids are created when a Texture packer file has been loaded
- *
- * @method fromFrame
- * @static
- * @param frameId {String} The frame Id of the texture in the cache
- * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId
- */
- PIXI.Sprite.fromFrame = function(frameId)
- {
- var texture = PIXI.TextureCache[frameId];
- if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this);
- return new PIXI.Sprite(texture);
- };
- /**
- *
- * Helper function that creates a sprite that will contain a texture based on an image url
- * If the image is not in the texture cache it will be loaded
- *
- * @method fromImage
- * @static
- * @param imageId {String} The image url of the texture
- * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id
- */
- PIXI.Sprite.fromImage = function(imageId, crossorigin, scaleMode)
- {
- var texture = PIXI.Texture.fromImage(imageId, crossorigin, scaleMode);
- return new PIXI.Sprite(texture);
- };
- /**
- * @author Mat Groves http://matgroves.com/
- */
- /**
- * The SpriteBatch class is a really fast version of the DisplayObjectContainer
- * built solely for speed, so use when you need a lot of sprites or particles.
- * And it's extremely easy to use :
- var container = new PIXI.SpriteBatch();
-
- stage.addChild(container);
-
- for(var i = 0; i < 100; i++)
- {
- var sprite = new PIXI.Sprite.fromImage("myImage.png");
- container.addChild(sprite);
- }
- * And here you have a hundred sprites that will be renderer at the speed of light
- *
- * @class SpriteBatch
- * @constructor
- * @param texture {Texture}
- */
- PIXI.SpriteBatch = function(texture)
- {
- PIXI.DisplayObjectContainer.call( this);
- this.textureThing = texture;
- this.ready = false;
- };
- PIXI.SpriteBatch.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
- PIXI.SpriteBatch.constructor = PIXI.SpriteBatch;
- /*
- * Initialises the spriteBatch
- *
- * @method initWebGL
- * @param gl {WebGLContext} the current WebGL drawing context
- */
- PIXI.SpriteBatch.prototype.initWebGL = function(gl)
- {
- // TODO only one needed for the whole engine really?
- this.fastSpriteBatch = new PIXI.WebGLFastSpriteBatch(gl);
- this.ready = true;
- };
- /*
- * Updates the object transform for rendering
- *
- * @method updateTransform
- * @private
- */
- PIXI.SpriteBatch.prototype.updateTransform = function()
- {
- // TODO dont need to!
- PIXI.DisplayObject.prototype.updateTransform.call( this );
- // PIXI.DisplayObjectContainer.prototype.updateTransform.call( this );
- };
- /**
- * Renders the object using the WebGL renderer
- *
- * @method _renderWebGL
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.SpriteBatch.prototype._renderWebGL = function(renderSession)
- {
- if(!this.visible || this.alpha <= 0 || !this.children.length)return;
- if(!this.ready)this.initWebGL( renderSession.gl );
-
- renderSession.spriteBatch.stop();
-
- renderSession.shaderManager.activateShader(renderSession.shaderManager.fastShader);
-
- this.fastSpriteBatch.begin(this, renderSession);
- this.fastSpriteBatch.render(this);
- renderSession.shaderManager.activateShader(renderSession.shaderManager.defaultShader);
- renderSession.spriteBatch.start();
-
- };
- /**
- * Renders the object using the Canvas renderer
- *
- * @method _renderCanvas
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.SpriteBatch.prototype._renderCanvas = function(renderSession)
- {
- var context = renderSession.context;
- context.globalAlpha = this.worldAlpha;
- PIXI.DisplayObject.prototype.updateTransform.call(this);
- var transform = this.worldTransform;
- // alow for trimming
-
- var isRotated = true;
- for (var i = 0; i < this.children.length; i++) {
-
- var child = this.children[i];
- if(!child.visible)continue;
- var texture = child.texture;
- var frame = texture.frame;
- context.globalAlpha = this.worldAlpha * child.alpha;
- if(child.rotation % (Math.PI * 2) === 0)
- {
- if(isRotated)
- {
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
- isRotated = false;
- }
- // this is the fastest way to optimise! - if rotation is 0 then we can avoid any kind of setTransform call
- context.drawImage(texture.baseTexture.source,
- frame.x,
- frame.y,
- frame.width,
- frame.height,
- ((child.anchor.x) * (-frame.width * child.scale.x) + child.position.x + 0.5) | 0,
- ((child.anchor.y) * (-frame.height * child.scale.y) + child.position.y + 0.5) | 0,
- frame.width * child.scale.x,
- frame.height * child.scale.y);
- }
- else
- {
- if(!isRotated)isRotated = true;
-
- PIXI.DisplayObject.prototype.updateTransform.call(child);
-
- var childTransform = child.worldTransform;
- // allow for trimming
-
- if (renderSession.roundPixels)
- {
- context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0);
- }
- else
- {
- context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty);
- }
- context.drawImage(texture.baseTexture.source,
- frame.x,
- frame.y,
- frame.width,
- frame.height,
- ((child.anchor.x) * (-frame.width) + 0.5) | 0,
- ((child.anchor.y) * (-frame.height) + 0.5) | 0,
- frame.width,
- frame.height);
-
- }
- // context.restore();
- }
- // context.restore();
- };
- /**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
- PIXI.FilterBlock = function()
- {
- this.visible = true;
- this.renderable = true;
- };
- /**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- * - Modified by Tom Slezakowski http://www.tomslezakowski.com @TomSlezakowski (24/03/2014) - Added dropShadowColor.
- */
- /**
- * 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
- * @param [style.dropShadow=false] {Boolean} Set a drop shadow for the text
- * @param [style.dropShadowColor='#000000'] {String} A fill style to be used on the dropshadow e.g 'red', '#00FF00'
- * @param [style.dropShadowAngle=Math.PI/4] {Number} Set a angle of the drop shadow
- * @param [style.dropShadowDistance=5] {Number} Set a distance of the drop shadow
- */
- 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
- * @param [style.dropShadow=false] {Boolean} Set a drop shadow for the text
- * @param [style.dropShadowColor='#000000'] {String} A fill style to be used on the dropshadow e.g 'red', '#00FF00'
- * @param [style.dropShadowAngle=Math.PI/4] {Number} Set a angle of the drop shadow
- * @param [style.dropShadowDistance=5] {Number} Set a distance of the drop shadow
- */
- 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;
- style.wordWrapWidth = style.wordWrapWidth || 100;
-
- style.dropShadow = style.dropShadow || false;
- style.dropShadowAngle = style.dropShadowAngle || Math.PI / 6;
- style.dropShadowDistance = style.dropShadowDistance || 4;
- style.dropShadowColor = style.dropShadowColor || 'black';
- 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);
- }
- var width = maxLineWidth + this.style.strokeThickness;
- if(this.style.dropShadow)width += this.style.dropShadowDistance;
- this.canvas.width = width;
- //calculate text height
- var lineHeight = this.determineFontHeight('font: ' + this.style.font + ';') + this.style.strokeThickness;
-
- var height = lineHeight * lines.length;
- if(this.style.dropShadow)height += this.style.dropShadowDistance;
- this.canvas.height = height;
- if(navigator.isCocoonJS) this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
-
- this.context.font = this.style.font;
- this.context.strokeStyle = this.style.stroke;
- this.context.lineWidth = this.style.strokeThickness;
- this.context.textBaseline = 'top';
- var linePositionX;
- var linePositionY;
- if(this.style.dropShadow)
- {
- this.context.fillStyle = this.style.dropShadowColor;
- var xShadowOffset = Math.sin(this.style.dropShadowAngle) * this.style.dropShadowDistance;
- var yShadowOffset = Math.cos(this.style.dropShadowAngle) * this.style.dropShadowDistance;
- for (i = 0; i < lines.length; i++)
- {
- linePositionX = this.style.strokeThickness / 2;
- linePositionY = this.style.strokeThickness / 2 + i * lineHeight;
- if(this.style.align === 'right')
- {
- linePositionX += maxLineWidth - lineWidths[i];
- }
- else if(this.style.align === 'center')
- {
- linePositionX += (maxLineWidth - lineWidths[i]) / 2;
- }
- if(this.style.fill)
- {
- this.context.fillText(lines[i], linePositionX + xShadowOffset, linePositionY + yShadowOffset);
- }
- // if(dropShadow)
- }
- }
- //set canvas text styles
- this.context.fillStyle = this.style.fill;
-
- //draw lines line by line
- for (i = 0; i < lines.length; i++)
- {
- linePositionX = this.style.strokeThickness / 2;
- linePositionY = this.style.strokeThickness / 2 + i * lineHeight;
- if(this.style.align === 'right')
- {
- linePositionX += maxLineWidth - lineWidths[i];
- }
- else if(this.style.align === 'center')
- {
- linePositionX += (maxLineWidth - lineWidths[i]) / 2;
- }
- if(this.style.stroke && this.style.strokeThickness)
- {
- this.context.strokeText(lines[i], linePositionX, linePositionY);
- }
- if(this.style.fill)
- {
- this.context.fillText(lines[i], linePositionX, linePositionY);
- }
- // if(dropShadow)
- }
- 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
- */
- /**
- * 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<j; i++)
- {
- this.children[i].updateTransform();
- }
- if(this.dirty)
- {
- this.dirty = false;
- // update interactive!
- this.interactionManager.dirty = true;
- }
- if(this.interactive)this.interactionManager.update();
- };
- /**
- * Sets the background color for the stage
- *
- * @method setBackgroundColor
- * @param backgroundColor {Number} the color of the background, easiest way to pass this in is in hex format
- * like: 0xFFFFFF for white
- */
- PIXI.Stage.prototype.setBackgroundColor = function(backgroundColor)
- {
- this.backgroundColor = backgroundColor || 0x000000;
- this.backgroundColorSplit = PIXI.hex2rgb(this.backgroundColor);
- var hex = this.backgroundColor.toString(16);
- hex = '000000'.substr(0, 6 - hex.length) + hex;
- this.backgroundColorString = '#' + hex;
- };
- /**
- * This will return the point containing global coords of the mouse.
- *
- * @method getMousePosition
- * @return {Point} The point containing the coords of the global InteractionData position.
- */
- PIXI.Stage.prototype.getMousePosition = function()
- {
- return this.interactionManager.mouse.global;
- };
- /**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
-
- // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
- // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
- // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
- // MIT license
- /**
- * A polyfill for requestAnimationFrame
- * You can actually use both requestAnimationFrame and requestAnimFrame,
- * you will still benefit from the polyfill
- *
- * @method requestAnimationFrame
- */
- /**
- * A polyfill for cancelAnimationFrame
- *
- * @method cancelAnimationFrame
- */
- var lastTime = 0;
- var vendors = ['ms', 'moz', 'webkit', 'o'];
- for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
- window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
- window[vendors[x] + 'CancelRequestAnimationFrame'];
- }
- if (!window.requestAnimationFrame) {
- window.requestAnimationFrame = function(callback) {
- var currTime = new Date().getTime();
- var timeToCall = Math.max(0, 16 - (currTime - lastTime));
- var id = window.setTimeout(function() { callback(currTime + timeToCall); },
- timeToCall);
- lastTime = currTime + timeToCall;
- return id;
- };
- }
- if (!window.cancelAnimationFrame) {
- window.cancelAnimationFrame = function(id) {
- clearTimeout(id);
- };
- }
- window.requestAnimFrame = window.requestAnimationFrame;
- /**
- * Converts a hex color number to an [R, G, B] array
- *
- * @method hex2rgb
- * @param hex {Number}
- */
- PIXI.hex2rgb = function(hex) {
- return [(hex >> 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<activexmodes.length; i++)
- {
- try{
- return new window.ActiveXObject(activexmodes[i]);
- }
- catch(e) {
- //suppress error
- }
- }
- }
- else if (window.XMLHttpRequest) // if Mozilla, Safari etc
- {
- return new window.XMLHttpRequest();
- }
- else
- {
- return false;
- }
- };
- /*
- PIXI.packColorRGBA = function(r, g, b, a)//r, g, b, a)
- {
- // console.log(r, b, c, d)
- return (Math.floor((r)*63) << 18) | (Math.floor((g)*63) << 12) | (Math.floor((b)*63) << 6);// | (Math.floor((a)*63))
- // i = i | (Math.floor((a)*63));
- // return i;
- // var r = (i / 262144.0 ) / 64;
- // var g = (i / 4096.0)%64 / 64;
- // var b = (i / 64.0)%64 / 64;
- // var a = (i)%64 / 64;
-
- // console.log(r, g, b, a);
- // return i;
- };
- */
- /*
- PIXI.packColorRGB = function(r, g, b)//r, g, b, a)
- {
- return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255));
- };
- PIXI.unpackColorRGB = function(r, g, b)//r, g, b, a)
- {
- return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255));
- };
- */
- /**
- * Checks whether the Canvas BlendModes are supported by the current browser
- *
- * @method canUseNewCanvasBlendModes
- * @return {Boolean} whether they are supported
- */
- PIXI.canUseNewCanvasBlendModes = function()
- {
- var canvas = document.createElement('canvas');
- canvas.width = 1;
- canvas.height = 1;
- var context = canvas.getContext('2d');
- context.fillStyle = '#000';
- context.fillRect(0,0,1,1);
- context.globalCompositeOperation = 'multiply';
- context.fillStyle = '#fff';
- context.fillRect(0,0,1,1);
- return context.getImageData(0,0,1,1).data[0] === 0;
- };
- /**
- * Given a number, this function returns the closest number that is a power of two
- * this function is taken from Starling Framework as its pretty neat ;)
- *
- * @method getNextPowerOfTwo
- * @param number {Number}
- * @return {Number} the closest number that is a power of two
- */
- PIXI.getNextPowerOfTwo = function(number)
- {
- if (number > 0 && (number & (number - 1)) === 0) // see: http://goo.gl/D9kPj
- return number;
- else
- {
- var result = 1;
- while (result < number) result <<= 1;
- return result;
- }
- };
- /**
- * @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 listeners
- * @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;
- };
- };
- /*
- 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._glTextures[gl.id]);
- // 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;
- };
- /**
- * The Default Vertex shader source
- * @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;
- this.renderSession.renderer = this;
- 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();
- // interaction
- if(stage._interactive)
- {
- //need to add some events!
- if(!stage._interactiveEventsAdded)
- {
- stage._interactiveEventsAdded = true;
- stage.interactionManager.setTarget(this);
- }
- }
-
- 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 <mattdesl> 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 = 2000;//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)
- {
- var texture = sprite.texture;
- // check texture..
- if(texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
- {
- this.flush();
- this.currentBaseTexture = 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;
- // 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 + texture.frame.width;
- h1 = trim.y - aY * trim.height;
- h0 = h1 + texture.frame.height;
- }
- else
- {
- w0 = (texture.frame.width ) * (1-aX);
- w1 = (texture.frame.width ) * -aX;
- h0 = texture.frame.height * (1-aY);
- h1 = texture.frame.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.tileScaleOffset.x;
- tilingSprite.tilePosition.y %= texture.baseTexture.height * tilingSprite.tileScaleOffset.y;
- var offsetX = tilingSprite.tilePosition.x/(texture.baseTexture.width*tilingSprite.tileScaleOffset.x);
- var offsetY = tilingSprite.tilePosition.y/(texture.baseTexture.height*tilingSprite.tileScaleOffset.y);
- 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 <mattdesl> 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<j; i++)
- {
- this.renderSprite(children[i]);
- }
- this.flush();
- };
- PIXI.WebGLFastSpriteBatch.prototype.renderSprite = function(sprite)
- {
- //sprite = children[i];
- if(!sprite.visible)return;
-
- // TODO trim??
- if(sprite.texture.baseTexture !== this.currentBaseTexture)
- {
- this.flush();
- this.currentBaseTexture = sprite.texture.baseTexture;
-
- if(!sprite.texture._uvs)return;
- }
- var uvs, verticies = this.vertices, width, height, w0, w1, h0, h1, index;
- uvs = sprite.texture._uvs;
- width = sprite.texture.frame.width;
- height = sprite.texture.frame.height;
- 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 - sprite.anchor.x * trim.width;
- w0 = w1 + sprite.texture.frame.width;
- h1 = trim.y - sprite.anchor.y * trim.height;
- h0 = h1 + sprite.texture.frame.height;
- }
- else
- {
- w0 = (sprite.texture.frame.width ) * (1-sprite.anchor.x);
- w1 = (sprite.texture.frame.width ) * -sprite.anchor.x;
- h0 = sprite.texture.frame.height * (1-sprite.anchor.y);
- h1 = sprite.texture.frame.height * -sprite.anchor.y;
- }
- index = this.currentBatchSize * 4 * this.vertSize;
- // xy
- verticies[index++] = w1;
- verticies[index++] = h1;
- verticies[index++] = sprite.position.x;
- verticies[index++] = sprite.position.y;
- //scale
- verticies[index++] = sprite.scale.x;
- verticies[index++] = sprite.scale.y;
- //rotation
- verticies[index++] = sprite.rotation;
- // uv
- verticies[index++] = uvs.x0;
- verticies[index++] = uvs.y1;
- // color
- verticies[index++] = sprite.alpha;
-
- // xy
- verticies[index++] = w0;
- verticies[index++] = h1;
- verticies[index++] = sprite.position.x;
- verticies[index++] = sprite.position.y;
- //scale
- verticies[index++] = sprite.scale.x;
- verticies[index++] = sprite.scale.y;
- //rotation
- verticies[index++] = sprite.rotation;
- // uv
- verticies[index++] = uvs.x1;
- verticies[index++] = uvs.y1;
- // color
- verticies[index++] = sprite.alpha;
-
- // xy
- verticies[index++] = w0;
- verticies[index++] = h0;
- verticies[index++] = sprite.position.x;
- verticies[index++] = sprite.position.y;
- //scale
- verticies[index++] = sprite.scale.x;
- verticies[index++] = sprite.scale.y;
- //rotation
- verticies[index++] = sprite.rotation;
- // uv
- verticies[index++] = uvs.x2;
- verticies[index++] = uvs.y2;
- // color
- verticies[index++] = sprite.alpha;
-
- // xy
- verticies[index++] = w1;
- verticies[index++] = h0;
- verticies[index++] = sprite.position.x;
- verticies[index++] = sprite.position.y;
- //scale
- verticies[index++] = sprite.scale.x;
- verticies[index++] = sprite.scale.y;
- //rotation
- verticies[index++] = sprite.rotation;
- // uv
- verticies[index++] = uvs.x3;
- verticies[index++] = uvs.y3;
- // color
- verticies[index++] = sprite.alpha;
- // increment the batchs
- this.currentBatchSize++;
- if(this.currentBatchSize >= 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;
- // console.log(this.width)
- 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;
- filterBlock._filterArea = filterBlock.target.filterArea || filterBlock.target.getBounds();
- // 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._filterArea.x;
- this.offsetY += filterBlock._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);
- var filterArea = filterBlock._filterArea;// filterBlock.target.getBounds();///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._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);
- outputTexture.resize(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, true);//this.transparent);
- }
- else
- {
- var currentFilter = this.filterStack[this.filterStack.length-1];
- filterArea = currentFilter._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._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);
- //console.log(this.vertexArray)
- //console.log(this.uvArray)
- //console.log(sizeX + " : " + sizeY)
- 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;
- }
- // console.log(this.uvArray )
- 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;
- }
- this._cachedSprite.alpha = this.alpha;
- 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<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- renderSession.spriteBatch.stop();
- }
- if(this._filters)renderSession.filterManager.popFilter();
- if(this._mask)renderSession.maskManager.popMask(renderSession);
-
- renderSession.drawCount++;
- renderSession.spriteBatch.start();
- }
- };
- /**
- * Renders the object using the Canvas renderer
- *
- * @method _renderCanvas
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.Graphics.prototype._renderCanvas = 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;
-
- var context = renderSession.context;
- var transform = this.worldTransform;
-
- if(this.blendMode !== renderSession.currentBlendMode)
- {
- renderSession.currentBlendMode = this.blendMode;
- context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
- }
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
- PIXI.CanvasGraphics.renderGraphics(this, context);
- // simple render children!
- for(var i=0, j=this.children.length; i<j; i++)
- {
- this.children[i]._renderCanvas(renderSession);
- }
- };
- /**
- * Retrieves the bounds of the graphic shape as a rectangle object
- *
- * @method getBounds
- * @return {Rectangle} the rectangular bounding area
- */
- PIXI.Graphics.prototype.getBounds = function( matrix )
- {
- if(!this.bounds)this.updateBounds();
- var w0 = this.bounds.x;
- var w1 = this.bounds.width + this.bounds.x;
- var h0 = this.bounds.y;
- var h1 = this.bounds.height + this.bounds.y;
- var worldTransform = matrix || this.worldTransform;
- var a = worldTransform.a;
- var b = worldTransform.c;
- var c = worldTransform.b;
- var d = worldTransform.d;
- var tx = worldTransform.tx;
- var ty = worldTransform.ty;
- var x1 = a * w1 + c * h1 + tx;
- var y1 = d * h1 + b * w1 + ty;
- var x2 = a * w0 + c * h1 + tx;
- var y2 = d * h1 + b * w0 + ty;
- var x3 = a * w0 + c * h0 + tx;
- var y3 = d * h0 + b * w0 + ty;
- var x4 = a * w1 + c * h0 + tx;
- var y4 = d * h0 + b * w1 + ty;
- var maxX = -Infinity;
- var maxY = -Infinity;
- var minX = Infinity;
- var minY = Infinity;
- minX = x1 < minX ? x1 : minX;
- minX = x2 < minX ? x2 : minX;
- minX = x3 < minX ? x3 : minX;
- minX = x4 < minX ? x4 : minX;
- minY = y1 < minY ? y1 : minY;
- minY = y2 < minY ? y2 : minY;
- minY = y3 < minY ? y3 : minY;
- minY = y4 < minY ? y4 : minY;
- maxX = x1 > maxX ? x1 : maxX;
- maxX = x2 > maxX ? x2 : maxX;
- maxX = x3 > maxX ? x3 : maxX;
- maxX = x4 > maxX ? x4 : maxX;
- maxY = y1 > maxY ? y1 : maxY;
- maxY = y2 > maxY ? y2 : maxY;
- maxY = y3 > maxY ? y3 : maxY;
- maxY = y4 > maxY ? y4 : maxY;
- 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.alpha = this.alpha;
- // 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/
- */
- /**
- * A tiling sprite is a fast way of rendering a tiling image
- *
- * @class TilingSprite
- * @extends Sprite
- * @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;
- };
- PIXI.TilingSprite.prototype.setTexture = function(texture)
- {
- if(this.texture === texture)return;
- this.texture = texture;
- this.refreshTexture = true;
- /*
- if(this.tilingTexture)
- {
- this.generateTilingTexture(true);
- }
- */
- /*
- // stop current texture;
- if(this.texture.baseTexture !== texture.baseTexture)
- {
- this.textureChange = true;
- this.texture = texture;
- }
- else
- {
- this.texture = texture;
- }
- this.updateFrame = true;*/
- this.cachedTint = 0xFFFFFF;
- };
- /**
- * 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)
- {
- 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.refreshTexture)
- {
- this.generateTilingTexture(true);
- if(this.tilingTexture && this.tilingTexture.needsUpdate)
- {
- //TODO - tweaking
- PIXI.updateWebGLTexture(this.tilingTexture.baseTexture, renderSession.gl);
- this.tilingTexture.needsUpdate = false;
- // this.tilingTexture._uvs = null;
- }
- }
- else renderSession.spriteBatch.renderTilingSprite(this);
-
- // simple render children!
- for(i=0,j=this.children.length; i<j; i++)
- {
- this.children[i]._renderWebGL(renderSession);
- }
- renderSession.spriteBatch.stop();
- if(this.filters)renderSession.filterManager.popFilter();
- if(this.mask)renderSession.maskManager.popMask(renderSession);
-
- renderSession.spriteBatch.start();
- };
- /**
- * Renders the object using the Canvas renderer
- *
- * @method _renderCanvas
- * @param renderSession {RenderSession}
- * @private
- */
- PIXI.TilingSprite.prototype._renderCanvas = function(renderSession)
- {
- if(this.visible === false || this.alpha === 0)return;
-
- var context = renderSession.context;
- if(this._mask)
- {
- renderSession.maskManager.pushMask(this._mask, context);
- }
- context.globalAlpha = this.worldAlpha;
-
- var transform = this.worldTransform;
- // allow for trimming
- //(this.anchor.x) * -frame.width,
- // (this.anchor.y) * -frame.height,
-
- context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx , transform.ty);
- if(!this.__tilePattern || this.refreshTexture)
- {
- this.generateTilingTexture(false);
-
- if(this.tilingTexture)
- {
- this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');
- }
- else
- {
- return;
- }
- }
- // check blend mode
- if(this.blendMode !== renderSession.currentBlendMode)
- {
- renderSession.currentBlendMode = this.blendMode;
- context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
- }
- context.beginPath();
- var tilePosition = this.tilePosition;
- var tileScale = this.tileScale;
- tilePosition.x %= this.tilingTexture.baseTexture.width;
- tilePosition.y %= this.tilingTexture.baseTexture.height;
- // offset
- context.scale(tileScale.x,tileScale.y);
- context.translate(tilePosition.x, tilePosition.y);
- context.fillStyle = this.__tilePattern;
- // make sure to account for the anchor point..
- context.fillRect(-tilePosition.x + (this.anchor.x * -this._width),-tilePosition.y + (this.anchor.y * -this._height),
- this._width / tileScale.x, this._height / tileScale.y);
- context.scale(1/tileScale.x, 1/tileScale.y);
- context.translate(-tilePosition.x, -tilePosition.y);
- context.closePath();
- if(this._mask)
- {
- renderSession.maskManager.popMask(renderSession.context);
- }
- };
- /**
- * Returns the framing rectangle of the sprite as a PIXI.Rectangle object
- *
- * @method getBounds
- * @return {Rectangle} the framing rectangle
- */
- PIXI.TilingSprite.prototype.getBounds = function()
- {
- var width = this._width;
- var height = this._height;
- var w0 = width * (1-this.anchor.x);
- var w1 = width * -this.anchor.x;
- var h0 = height * (1-this.anchor.y);
- var h1 = height * -this.anchor.y;
- var worldTransform = this.worldTransform;
- var a = worldTransform.a;
- var b = worldTransform.c;
- var c = worldTransform.b;
- var d = worldTransform.d;
- var tx = worldTransform.tx;
- var ty = worldTransform.ty;
-
- var x1 = a * w1 + c * h1 + tx;
- var y1 = d * h1 + b * w1 + ty;
- var x2 = a * w0 + c * h1 + tx;
- var y2 = d * h1 + b * w0 + ty;
- var x3 = a * w0 + c * h0 + tx;
- var y3 = d * h0 + b * w0 + ty;
- var x4 = a * w1 + c * h0 + tx;
- var y4 = d * h0 + b * w1 + ty;
- var maxX = -Infinity;
- var maxY = -Infinity;
- var minX = Infinity;
- var minY = Infinity;
- minX = x1 < minX ? x1 : minX;
- minX = x2 < minX ? x2 : minX;
- minX = x3 < minX ? x3 : minX;
- minX = x4 < minX ? x4 : minX;
- minY = y1 < minY ? y1 : minY;
- minY = y2 < minY ? y2 : minY;
- minY = y3 < minY ? y3 : minY;
- minY = y4 < minY ? y4 : minY;
- maxX = x1 > maxX ? x1 : maxX;
- maxX = x2 > maxX ? x2 : maxX;
- maxX = x3 > maxX ? x3 : maxX;
- maxX = x4 > maxX ? x4 : maxX;
- maxY = y1 > maxY ? y1 : maxY;
- maxY = y2 > maxY ? y2 : maxY;
- maxY = y3 > maxY ? y3 : maxY;
- maxY = y4 > maxY ? y4 : maxY;
- 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;
- var newTextureRequired = false;
- if(!forcePowerOfTwo)
- {
- if(isFrame)
- {
- targetWidth = frame.width;
- targetHeight = frame.height;
-
- newTextureRequired = true;
-
- }
- }
- else
- {
- targetWidth = PIXI.getNextPowerOfTwo(frame.width);
- targetHeight = PIXI.getNextPowerOfTwo(frame.height);
- if(frame.width !== targetWidth && frame.height !== targetHeight)newTextureRequired = true;
- }
- if(newTextureRequired)
- {
- var canvasBuffer;
- if(this.tilingTexture && this.tilingTexture.isTiling)
- {
- canvasBuffer = this.tilingTexture.canvasBuffer;
- canvasBuffer.resize(targetWidth, targetHeight);
- this.tilingTexture.baseTexture.width = targetWidth;
- this.tilingTexture.baseTexture.height = targetHeight;
- this.tilingTexture.needsUpdate = true;
- }
- else
- {
- canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight);
- this.tilingTexture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
- this.tilingTexture.canvasBuffer = canvasBuffer;
- this.tilingTexture.isTiling = true;
- }
-
- canvasBuffer.context.drawImage(texture.baseTexture.source,
- frame.x,
- frame.y,
- frame.width,
- frame.height,
- 0,
- 0,
- targetWidth,
- targetHeight);
- this.tileScaleOffset.x = frame.width / targetWidth;
- this.tileScaleOffset.y = frame.height / targetHeight;
- }
- else
- {
- //TODO - switching?
- if(this.tilingTexture && this.tilingTexture.isTiling)
- {
- // destroy the tiling texture!
- // TODO could store this somewhere?
- this.tilingTexture.destroy(true);
- }
- this.tileScaleOffset.x = 1;
- this.tileScaleOffset.y = 1;
- this.tilingTexture = texture;
- }
- this.refreshTexture = false;
- this.tilingTexture.baseTexture._powerOf2 = true;
- };
- /**
- * @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;
- //TODO will be used for futer pixi 1.5...
- this.id = PIXI.BaseTextureCacheIdGenerator++;
- // used for webGL
- this._glTextures = [];
-
- 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;
-
- };
- 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];
-
- if(crossorigin === undefined)crossorigin = true;
- 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;
- this._uvs = null;
-
- 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];
- delete PIXI.TextureCache[id];
- delete PIXI.BaseTextureCache[id];
- 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<j; i++)
- {
- children[i].updateTransform();
- }
- // update the textures!
- PIXI.WebGLRenderer.updateTextures();
- //
- this.renderer.renderDisplayObject(displayObject, this.projection, this.textureBuffer.frameBuffer);
- displayObject.worldTransform = originalWorldTransform;
- };
- /**
- * This function will draw the display object to the texture.
- *
- * @method renderCanvas
- * @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.renderCanvas = function(displayObject, position, clear)
- {
- var children = displayObject.children;
- var originalWorldTransform = displayObject.worldTransform;
- displayObject.worldTransform = PIXI.RenderTexture.tempMatrix;
- if(position)
- {
- displayObject.worldTransform.tx = position.x;
- displayObject.worldTransform.ty = position.y;
- }
- for(var i = 0, j = children.length; i < j; i++)
- {
- children[i].updateTransform();
- }
- if(clear)this.textureBuffer.clear();
- var context = this.textureBuffer.context;
- this.renderer.renderDisplayObject(displayObject, context);
- context.setTransform(1,0,0,1,0,0);
- displayObject.worldTransform = originalWorldTransform;
- };
- PIXI.RenderTexture.tempMatrix = new PIXI.Matrix();
- /**
- * @author Mat Groves http://matgroves.com/ @Doormat23
- */
- if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports = PIXI;
- }
- exports.PIXI = PIXI;
- } else if (typeof define !== 'undefined' && define.amd) {
- define('PIXI', (function() { return root.PIXI = PIXI; })() );
- } else {
- root.PIXI = PIXI;
- }
- }).call(this);
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- *
- * @overview
- *
- * Phaser - http://phaser.io
- *
- * v2.0.3 "Allorallen" - Built: Fri Apr 11 2014 13:08:30
- *
- * By Richard Davey http://www.photonstorm.com @photonstorm
- *
- * Phaser is a fun, free and fast 2D game framework for making HTML5 games
- * for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
- *
- * Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
- * Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
- * Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
- *
- * Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser
- * and my love of framework development originate.
- *
- * Follow development at http://phaser.io and on our forum
- *
- * "If you want your children to be intelligent, read them fairy tales."
- * "If you want them to be more intelligent, read them more fairy tales."
- * -- Albert Einstein
- */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- (function(){
- var root = this;
- /* global Phaser:true */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * @namespace Phaser
- */
- var Phaser = Phaser || {
- VERSION: '<%= version %>',
- DEV_VERSION: '2.0.3',
- GAMES: [],
- AUTO: 0,
- CANVAS: 1,
- WEBGL: 2,
- HEADLESS: 3,
- NONE: 0,
- LEFT: 1,
- RIGHT: 2,
- UP: 3,
- DOWN: 4,
- SPRITE: 0,
- BUTTON: 1,
- IMAGE: 2,
- GRAPHICS: 3,
- TEXT: 4,
- TILESPRITE: 5,
- BITMAPTEXT: 6,
- GROUP: 7,
- RENDERTEXTURE: 8,
- TILEMAP: 9,
- TILEMAPLAYER: 10,
- EMITTER: 11,
- POLYGON: 12,
- BITMAPDATA: 13,
- CANVAS_FILTER: 14,
- WEBGL_FILTER: 15,
- ELLIPSE: 16,
- SPRITEBATCH: 17,
- RETROFONT: 18,
- // The various blend modes supported by pixi / phaser
- 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
- scaleModes: {
- DEFAULT:0,
- LINEAR:0,
- NEAREST:1
- }
- };
- PIXI.InteractionManager = function () {
- // We don't need this in Pixi, so we've removed it to save space
- // however the Stage object expects a reference to it, so here is a dummy entry.
- };
- /* jshint supernew: true */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * @class Phaser.Utils
- * @static
- */
- Phaser.Utils = {
- /**
- * Get a unit dimension from a string.
- *
- * @method Phaser.Utils.parseDimension
- * @param {string|number} size - The size to parse.
- * @param {number} dimension - The window dimension to check.
- * @return {number} The parsed dimension.
- */
- parseDimension: function (size, dimension) {
- var f = 0;
- var px = 0;
- if (typeof size === 'string')
- {
- // %?
- if (size.substr(-1) === '%')
- {
- f = parseInt(size, 10) / 100;
- if (dimension === 0)
- {
- px = window.innerWidth * f;
- }
- else
- {
- px = window.innerHeight * f;
- }
- }
- else
- {
- px = parseInt(size, 10);
- }
- }
- else
- {
- px = size;
- }
- return px;
- },
- /**
- * A standard Fisher-Yates Array shuffle implementation.
- * @method Phaser.Utils.shuffle
- * @param {array} array - The array to shuffle.
- * @return {array} The shuffled array.
- */
- shuffle: function (array) {
- for (var i = array.length - 1; i > 0; i--)
- {
- var j = Math.floor(Math.random() * (i + 1));
- var temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- }
- return array;
- },
- /**
- * Javascript string pad http://www.webtoolkit.info/.
- * pad = the string to pad it out with (defaults to a space)
- * dir = 1 (left), 2 (right), 3 (both)
- * @method Phaser.Utils.pad
- * @param {string} str - The target string.
- * @param {number} len - The number of characters to be added.
- * @param {number} pad - The string to pad it out with (defaults to a space).
- * @param {number} [dir=3] The direction dir = 1 (left), 2 (right), 3 (both).
- * @return {string} The padded string
- */
- pad: function (str, len, pad, dir) {
- if (typeof(len) == "undefined") { var len = 0; }
- if (typeof(pad) == "undefined") { var pad = ' '; }
- if (typeof(dir) == "undefined") { var dir = 3; }
- var padlen = 0;
- if (len + 1 >= str.length)
- {
- switch (dir)
- {
- case 1:
- str = new Array(len + 1 - str.length).join(pad) + str;
- break;
- case 3:
- var right = Math.ceil((padlen = len - str.length) / 2);
- var left = padlen - right;
- str = new Array(left+1).join(pad) + str + new Array(right+1).join(pad);
- break;
- default:
- str = str + new Array(len + 1 - str.length).join(pad);
- break;
- }
- }
- return str;
- },
- /**
- * This is a slightly modified version of jQuery.isPlainObject. A plain object is an object whose internal class property is [object Object].
- * @method Phaser.Utils.isPlainObject
- * @param {object} obj - The object to inspect.
- * @return {boolean} - true if the object is plain, otherwise false.
- */
- isPlainObject: function (obj) {
- // Not plain objects:
- // - Any object or value whose internal [[Class]] property is not "[object Object]"
- // - DOM nodes
- // - window
- if (typeof(obj) !== "object" || obj.nodeType || obj === obj.window)
- {
- return false;
- }
- // Support: Firefox <20
- // The try/catch suppresses exceptions thrown when attempting to access
- // the "constructor" property of certain host objects, ie. |window.location|
- // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
- try {
- if (obj.constructor && !({}).hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf"))
- {
- return false;
- }
- } catch (e) {
- return false;
- }
- // If the function hasn't returned already, we're confident that
- // |obj| is a plain object, created by {} or constructed with new Object
- return true;
- },
- /**
- * This is a slightly modified version of http://api.jquery.com/jQuery.extend/
- * @method Phaser.Utils.extend
- * @param {boolean} deep - Perform a deep copy?
- * @param {object} target - The target object to copy to.
- * @return {object} The extended object.
- */
- extend: function () {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
- // Handle a deep copy situation
- if (typeof target === "boolean")
- {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
- // extend Phaser if only one argument is passed
- if (length === i)
- {
- target = this;
- --i;
- }
- for (; i < length; i++)
- {
- // Only deal with non-null/undefined values
- if ((options = arguments[i]) != null)
- {
- // Extend the base object
- for (name in options)
- {
- src = target[name];
- copy = options[name];
- // Prevent never-ending loop
- if (target === copy)
- {
- continue;
- }
- // Recurse if we're merging plain objects or arrays
- if (deep && copy && (Phaser.Utils.isPlainObject(copy) || (copyIsArray = Array.isArray(copy))))
- {
- if (copyIsArray)
- {
- copyIsArray = false;
- clone = src && Array.isArray(src) ? src : [];
- }
- else
- {
- clone = src && Phaser.Utils.isPlainObject(src) ? src : {};
- }
- // Never move original objects, clone them
- target[name] = Phaser.Utils.extend(deep, clone, copy);
- // Don't bring in undefined values
- }
- else if (copy !== undefined)
- {
- target[name] = copy;
- }
- }
- }
- }
- // Return the modified object
- return target;
- }
- };
- /**
- * A polyfill for Function.prototype.bind
- */
- if (typeof Function.prototype.bind != 'function') {
- /* jshint freeze: false */
- 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 polyfill for Array.isArray
- */
- if (!Array.isArray)
- {
- Array.isArray = function (arg)
- {
- return Object.prototype.toString.call(arg) == '[object Array]';
- };
- }
- /**
- * A polyfill for Array.forEach
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
- */
- if (!Array.prototype.forEach)
- {
- Array.prototype.forEach = function(fun /*, thisArg */)
- {
- "use strict";
- if (this === void 0 || this === null)
- {
- throw new TypeError();
- }
- var t = Object(this);
- var len = t.length >>> 0;
- if (typeof fun !== "function")
- {
- throw new TypeError();
- }
- var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
- for (var i = 0; i < len; i++)
- {
- if (i in t)
- {
- fun.call(thisArg, t[i], i, t);
- }
- }
- };
- }
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a new Circle object with the center coordinate specified by the x and y parameters and the diameter specified by the diameter parameter. If you call this function without parameters, a circle with x, y, diameter and radius properties set to 0 is created.
- * @class Circle
- * @classdesc Phaser - Circle
- * @constructor
- * @param {number} [x=0] - The x coordinate of the center of the circle.
- * @param {number} [y=0] - The y coordinate of the center of the circle.
- * @param {number} [diameter=0] - The diameter of the circle.
- * @return {Phaser.Circle} This circle object
- */
- Phaser.Circle = function (x, y, diameter) {
- x = x || 0;
- y = y || 0;
- diameter = diameter || 0;
- /**
- * @property {number} x - The x coordinate of the center of the circle.
- */
- this.x = x;
- /**
- * @property {number} y - The y coordinate of the center of the circle.
- */
- this.y = y;
- /**
- * @property {number} _diameter - The diameter of the circle.
- * @private
- */
- this._diameter = diameter;
- if (diameter > 0)
- {
- /**
- * @property {number} _radius - The radius of the circle.
- * @private
- */
- this._radius = diameter * 0.5;
- }
- else
- {
- this._radius = 0;
- }
- };
- Phaser.Circle.prototype = {
- /**
- * The circumference of the circle.
- * @method Phaser.Circle#circumference
- * @return {number}
- */
- circumference: function () {
- return 2 * (Math.PI * this._radius);
- },
- /**
- * Sets the members of Circle to the specified values.
- * @method Phaser.Circle#setTo
- * @param {number} x - The x coordinate of the center of the circle.
- * @param {number} y - The y coordinate of the center of the circle.
- * @param {number} diameter - The diameter of the circle in pixels.
- * @return {Circle} This circle object.
- */
- setTo: function (x, y, diameter) {
- this.x = x;
- this.y = y;
- this._diameter = diameter;
- this._radius = diameter * 0.5;
- return this;
- },
- /**
- * Copies the x, y and diameter properties from any given object to this Circle.
- * @method Phaser.Circle#copyFrom
- * @param {any} source - The object to copy from.
- * @return {Circle} This Circle object.
- */
- copyFrom: function (source) {
- return this.setTo(source.x, source.y, source.diameter);
- },
- /**
- * Copies the x, y and diameter properties from this Circle to any given object.
- * @method Phaser.Circle#copyTo
- * @param {any} dest - The object to copy to.
- * @return {Object} This dest object.
- */
- copyTo: function (dest) {
- dest.x = this.x;
- dest.y = this.y;
- dest.diameter = this._diameter;
- return dest;
- },
- /**
- * Returns the distance from the center of the Circle object to the given object
- * (can be Circle, Point or anything with x/y properties)
- * @method Phaser.Circle#distance
- * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
- * @param {boolean} [round] - Round the distance to the nearest integer (default false).
- * @return {number} The distance between this Point object and the destination Point object.
- */
- distance: function (dest, round) {
- if (typeof round === "undefined") { round = false; }
- if (round)
- {
- return Phaser.Math.distanceRound(this.x, this.y, dest.x, dest.y);
- }
- else
- {
- return Phaser.Math.distance(this.x, this.y, dest.x, dest.y);
- }
- },
- /**
- * Returns a new Circle object with the same values for the x, y, width, and height properties as this Circle object.
- * @method Phaser.Circle#clone
- * @param {Phaser.Circle} out - Optional Circle object. If given the values will be set into the object, otherwise a brand new Circle object will be created and returned.
- * @return {Phaser.Circle} The cloned Circle object.
- */
- clone: function (out) {
- if (typeof out === "undefined")
- {
- out = new Phaser.Circle(this.x, this.y, this.diameter);
- }
- else
- {
- out.setTo(this.x, this.y, this.diameter);
- }
- return out;
- },
- /**
- * Return true if the given x/y coordinates are within this Circle object.
- * @method Phaser.Circle#contains
- * @param {number} x - The X value of the coordinate to test.
- * @param {number} y - The Y value of the coordinate to test.
- * @return {boolean} True if the coordinates are within this circle, otherwise false.
- */
- contains: function (x, y) {
- return Phaser.Circle.contains(this, x, y);
- },
- /**
- * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
- * @method Phaser.Circle#circumferencePoint
- * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
- * @param {boolean} asDegrees - Is the given angle in radians (false) or degrees (true)?
- * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
- * @return {Phaser.Point} The Point object holding the result.
- */
- circumferencePoint: function (angle, asDegrees, out) {
- return Phaser.Circle.circumferencePoint(this, angle, asDegrees, out);
- },
- /**
- * Adjusts the location of the Circle object, as determined by its center coordinate, by the specified amounts.
- * @method Phaser.Circle#offset
- * @param {number} dx - Moves the x value of the Circle object by this amount.
- * @param {number} dy - Moves the y value of the Circle object by this amount.
- * @return {Circle} This Circle object.
- */
- offset: function (dx, dy) {
- this.x += dx;
- this.y += dy;
- return this;
- },
- /**
- * Adjusts the location of the Circle object using a Point object as a parameter. This method is similar to the Circle.offset() method, except that it takes a Point object as a parameter.
- * @method Phaser.Circle#offsetPoint
- * @param {Point} point A Point object to use to offset this Circle object (or any valid object with exposed x and y properties).
- * @return {Circle} This Circle object.
- */
- offsetPoint: function (point) {
- return this.offset(point.x, point.y);
- },
- /**
- * Returns a string representation of this object.
- * @method Phaser.Circle#toString
- * @return {string} a string representation of the instance.
- */
- toString: function () {
- return "[{Phaser.Circle (x=" + this.x + " y=" + this.y + " diameter=" + this.diameter + " radius=" + this.radius + ")}]";
- }
- };
- Phaser.Circle.prototype.constructor = Phaser.Circle;
- /**
- * The largest distance between any two points on the circle. The same as the radius * 2.
- * @name Phaser.Circle#diameter
- * @property {number} diameter - Gets or sets the diameter of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "diameter", {
- get: function () {
- return this._diameter;
- },
- set: function (value) {
- if (value > 0)
- {
- this._diameter = value;
- this._radius = value * 0.5;
- }
- }
- });
- /**
- * The length of a line extending from the center of the circle to any point on the circle itself. The same as half the diameter.
- * @name Phaser.Circle#radius
- * @property {number} radius - Gets or sets the radius of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "radius", {
- get: function () {
- return this._radius;
- },
- set: function (value) {
- if (value > 0)
- {
- this._radius = value;
- this._diameter = value * 2;
- }
- }
- });
- /**
- * The x coordinate of the leftmost point of the circle. Changing the left property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property.
- * @name Phaser.Circle#left
- * @propety {number} left - Gets or sets the value of the leftmost point of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "left", {
- get: function () {
- return this.x - this._radius;
- },
- set: function (value) {
- if (value > this.x)
- {
- this._radius = 0;
- this._diameter = 0;
- }
- else
- {
- this.radius = this.x - value;
- }
- }
- });
- /**
- * The x coordinate of the rightmost point of the circle. Changing the right property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property.
- * @name Phaser.Circle#right
- * @property {number} right - Gets or sets the value of the rightmost point of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "right", {
- get: function () {
- return this.x + this._radius;
- },
- set: function (value) {
- if (value < this.x)
- {
- this._radius = 0;
- this._diameter = 0;
- }
- else
- {
- this.radius = value - this.x;
- }
- }
- });
- /**
- * The sum of the y minus the radius property. Changing the top property of a Circle object has no effect on the x and y properties, but does change the diameter.
- * @name Phaser.Circle#top
- * @property {number} top - Gets or sets the top of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "top", {
- get: function () {
- return this.y - this._radius;
- },
- set: function (value) {
- if (value > this.y)
- {
- this._radius = 0;
- this._diameter = 0;
- }
- else
- {
- this.radius = this.y - value;
- }
- }
- });
- /**
- * The sum of the y and radius properties. Changing the bottom property of a Circle object has no effect on the x and y properties, but does change the diameter.
- * @name Phaser.Circle#bottom
- * @property {number} bottom - Gets or sets the bottom of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "bottom", {
- get: function () {
- return this.y + this._radius;
- },
- set: function (value) {
- if (value < this.y)
- {
- this._radius = 0;
- this._diameter = 0;
- }
- else
- {
- this.radius = value - this.y;
- }
- }
- });
- /**
- * The area of this Circle.
- * @name Phaser.Circle#area
- * @property {number} area - The area of this circle.
- * @readonly
- */
- Object.defineProperty(Phaser.Circle.prototype, "area", {
- get: function () {
- if (this._radius > 0)
- {
- return Math.PI * this._radius * this._radius;
- }
- else
- {
- return 0;
- }
- }
- });
- /**
- * Determines whether or not this Circle object is empty. Will return a value of true if the Circle objects diameter is less than or equal to 0; otherwise false.
- * If set to true it will reset all of the Circle objects properties to 0. A Circle object is empty if its diameter is less than or equal to 0.
- * @name Phaser.Circle#empty
- * @property {boolean} empty - Gets or sets the empty state of the circle.
- */
- Object.defineProperty(Phaser.Circle.prototype, "empty", {
- get: function () {
- return (this._diameter === 0);
- },
- set: function (value) {
- if (value === true)
- {
- this.setTo(0, 0, 0);
- }
- }
- });
- /**
- * Return true if the given x/y coordinates are within the Circle object.
- * @method Phaser.Circle.contains
- * @param {Phaser.Circle} a - The Circle to be checked.
- * @param {number} x - The X value of the coordinate to test.
- * @param {number} y - The Y value of the coordinate to test.
- * @return {boolean} True if the coordinates are within this circle, otherwise false.
- */
- Phaser.Circle.contains = function (a, x, y) {
- // Check if x/y are within the bounds first
- if (a.radius > 0 && x >= a.left && x <= a.right && y >= a.top && y <= a.bottom)
- {
- var dx = (a.x - x) * (a.x - x);
- var dy = (a.y - y) * (a.y - y);
- return (dx + dy) <= (a.radius * a.radius);
- }
- else
- {
- return false;
- }
- };
- /**
- * Determines whether the two Circle objects match. This method compares the x, y and diameter properties.
- * @method Phaser.Circle.equals
- * @param {Phaser.Circle} a - The first Circle object.
- * @param {Phaser.Circle} b - The second Circle object.
- * @return {boolean} A value of true if the object has exactly the same values for the x, y and diameter properties as this Circle object; otherwise false.
- */
- Phaser.Circle.equals = function (a, b) {
- return (a.x == b.x && a.y == b.y && a.diameter == b.diameter);
- };
- /**
- * Determines whether the two Circle objects intersect.
- * This method checks the radius distances between the two Circle objects to see if they intersect.
- * @method Phaser.Circle.intersects
- * @param {Phaser.Circle} a - The first Circle object.
- * @param {Phaser.Circle} b - The second Circle object.
- * @return {boolean} A value of true if the specified object intersects with this Circle object; otherwise false.
- */
- Phaser.Circle.intersects = function (a, b) {
- return (Phaser.Math.distance(a.x, a.y, b.x, b.y) <= (a.radius + b.radius));
- };
- /**
- * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
- * @method Phaser.Circle.circumferencePoint
- * @param {Phaser.Circle} a - The first Circle object.
- * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
- * @param {boolean} asDegrees - Is the given angle in radians (false) or degrees (true)?
- * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
- * @return {Phaser.Point} The Point object holding the result.
- */
- Phaser.Circle.circumferencePoint = function (a, angle, asDegrees, out) {
- if (typeof asDegrees === "undefined") { asDegrees = false; }
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- if (asDegrees === true)
- {
- angle = Phaser.Math.degToRad(angle);
- }
- out.x = a.x + a.radius * Math.cos(angle);
- out.y = a.y + a.radius * Math.sin(angle);
- return out;
- };
- /**
- * Checks if the given Circle and Rectangle objects intersect.
- * @method Phaser.Circle.intersectsRectangle
- * @param {Phaser.Circle} c - The Circle object to test.
- * @param {Phaser.Rectangle} r - The Rectangle object to test.
- * @return {boolean} True if the two objects intersect, otherwise false.
- */
- Phaser.Circle.intersectsRectangle = function (c, r) {
- var cx = Math.abs(c.x - r.x - r.halfWidth);
- var xDist = r.halfWidth + c.radius;
- if (cx > xDist)
- {
- return false;
- }
- var cy = Math.abs(c.y - r.y - r.halfHeight);
- var yDist = r.halfHeight + c.radius;
- if (cy > yDist)
- {
- return false;
- }
- if (cx <= r.halfWidth || cy <= r.halfHeight)
- {
- return true;
- }
- var xCornerDist = cx - r.halfWidth;
- var yCornerDist = cy - r.halfHeight;
- var xCornerDistSq = xCornerDist * xCornerDist;
- var yCornerDistSq = yCornerDist * yCornerDist;
- var maxCornerDistSq = c.radius * c.radius;
- return xCornerDistSq + yCornerDistSq <= maxCornerDistSq;
- };
- // Because PIXI uses its own Circle, we'll replace it with ours to avoid duplicating code or confusion.
- PIXI.Circle = Phaser.Circle;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a new Point. If you pass no parameters a Point is created set to (0,0).
- * @class Phaser.Point
- * @classdesc The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis.
- * @constructor
- * @param {number} x The horizontal position of this Point (default 0)
- * @param {number} y The vertical position of this Point (default 0)
- */
- Phaser.Point = function (x, y) {
- x = x || 0;
- y = y || 0;
- /**
- * @property {number} x - The x coordinate of the point.
- */
- this.x = x;
- /**
- * @property {number} y - The y coordinate of the point.
- */
- this.y = y;
- };
- Phaser.Point.prototype = {
- /**
- * Copies the x and y properties from any given object to this Point.
- * @method Phaser.Point#copyFrom
- * @param {any} source - The object to copy from.
- * @return {Point} This Point object.
- */
- copyFrom: function (source) {
- return this.setTo(source.x, source.y);
- },
- /**
- * Inverts the x and y values of this Point
- * @method Phaser.Point#invert
- * @return {Point} This Point object.
- */
- invert: function () {
- return this.setTo(this.y, this.x);
- },
- /**
- * Sets the x and y values of this Point object to the given coordinates.
- * @method Phaser.Point#setTo
- * @param {number} x - The horizontal position of this point.
- * @param {number} y - The vertical position of this point.
- * @return {Point} This Point object. Useful for chaining method calls.
- */
- setTo: function (x, y) {
- this.x = x || 0;
- this.y = y || ( (y !== 0) ? this.x : 0 );
- return this;
- },
- /**
- * Sets the x and y values of this Point object to the given coordinates.
- * @method Phaser.Point#set
- * @param {number} x - The horizontal position of this point.
- * @param {number} y - The vertical position of this point.
- * @return {Point} This Point object. Useful for chaining method calls.
- */
- set: function (x, y) {
- this.x = x || 0;
- this.y = y || ( (y !== 0) ? this.x : 0 );
- return this;
- },
- /**
- * Adds the given x and y values to this Point.
- * @method Phaser.Point#add
- * @param {number} x - The value to add to Point.x.
- * @param {number} y - The value to add to Point.y.
- * @return {Phaser.Point} This Point object. Useful for chaining method calls.
- */
- add: function (x, y) {
- this.x += x;
- this.y += y;
- return this;
- },
- /**
- * Subtracts the given x and y values from this Point.
- * @method Phaser.Point#subtract
- * @param {number} x - The value to subtract from Point.x.
- * @param {number} y - The value to subtract from Point.y.
- * @return {Phaser.Point} This Point object. Useful for chaining method calls.
- */
- subtract: function (x, y) {
- this.x -= x;
- this.y -= y;
- return this;
- },
- /**
- * Multiplies Point.x and Point.y by the given x and y values.
- * @method Phaser.Point#multiply
- * @param {number} x - The value to multiply Point.x by.
- * @param {number} y - The value to multiply Point.x by.
- * @return {Phaser.Point} This Point object. Useful for chaining method calls.
- */
- multiply: function (x, y) {
- this.x *= x;
- this.y *= y;
- return this;
- },
- /**
- * Divides Point.x and Point.y by the given x and y values.
- * @method Phaser.Point#divide
- * @param {number} x - The value to divide Point.x by.
- * @param {number} y - The value to divide Point.x by.
- * @return {Phaser.Point} This Point object. Useful for chaining method calls.
- */
- divide: function (x, y) {
- this.x /= x;
- this.y /= y;
- return this;
- },
- /**
- * Clamps the x value of this Point to be between the given min and max.
- * @method Phaser.Point#clampX
- * @param {number} min - The minimum value to clamp this Point to.
- * @param {number} max - The maximum value to clamp this Point to.
- * @return {Phaser.Point} This Point object.
- */
- clampX: function (min, max) {
- this.x = Phaser.Math.clamp(this.x, min, max);
- return this;
- },
- /**
- * Clamps the y value of this Point to be between the given min and max
- * @method Phaser.Point#clampY
- * @param {number} min - The minimum value to clamp this Point to.
- * @param {number} max - The maximum value to clamp this Point to.
- * @return {Phaser.Point} This Point object.
- */
- clampY: function (min, max) {
- this.y = Phaser.Math.clamp(this.y, min, max);
- return this;
- },
- /**
- * Clamps this Point object values to be between the given min and max.
- * @method Phaser.Point#clamp
- * @param {number} min - The minimum value to clamp this Point to.
- * @param {number} max - The maximum value to clamp this Point to.
- * @return {Phaser.Point} This Point object.
- */
- clamp: function (min, max) {
- this.x = Phaser.Math.clamp(this.x, min, max);
- this.y = Phaser.Math.clamp(this.y, min, max);
- return this;
- },
- /**
- * Creates a copy of the given Point.
- * @method Phaser.Point#clone
- * @param {Phaser.Point} [output] Optional Point object. If given the values will be set into this object, otherwise a brand new Point object will be created and returned.
- * @return {Phaser.Point} The new Point object.
- */
- clone: function (output) {
- if (typeof output === "undefined")
- {
- output = new Phaser.Point(this.x, this.y);
- }
- else
- {
- output.setTo(this.x, this.y);
- }
- return output;
- },
- /**
- * Copies the x and y properties from this Point to any given object.
- * @method Phaser.Point#copyTo
- * @param {any} dest - The object to copy to.
- * @return {Object} The dest object.
- */
- copyTo: function(dest) {
- dest.x = this.x;
- dest.y = this.y;
- return dest;
- },
- /**
- * Returns the distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties)
- * @method Phaser.Point#distance
- * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
- * @param {boolean} [round] - Round the distance to the nearest integer (default false).
- * @return {number} The distance between this Point object and the destination Point object.
- */
- distance: function (dest, round) {
- return Phaser.Point.distance(this, dest, round);
- },
- /**
- * Determines whether the given objects x/y values are equal to this Point object.
- * @method Phaser.Point#equals
- * @param {Phaser.Point} a - The first object to compare.
- * @return {boolean} A value of true if the Points are equal, otherwise false.
- */
- equals: function (a) {
- return (a.x == this.x && a.y == this.y);
- },
- /**
- * Rotates this Point around the x/y coordinates given to the desired angle.
- * @method Phaser.Point#rotate
- * @param {number} x - The x coordinate of the anchor point
- * @param {number} y - The y coordinate of the anchor point
- * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point to.
- * @param {boolean} asDegrees - Is the given rotation in radians (false) or degrees (true)?
- * @param {number} [distance] - An optional distance constraint between the Point and the anchor.
- * @return {Phaser.Point} The modified point object.
- */
- rotate: function (x, y, angle, asDegrees, distance) {
- return Phaser.Point.rotate(this, x, y, angle, asDegrees, distance);
- },
- /**
- * Calculates the length of the vector
- * @method Phaser.Point#getMagnitude
- * @return {number} the length of the vector
- */
- getMagnitude: function() {
- return Math.sqrt((this.x * this.x) + (this.y * this.y));
- },
- /**
- * Alters the length of the vector without changing the direction
- * @method Phaser.Point#setMagnitude
- * @param {number} magnitude the desired magnitude of the resulting vector
- * @return {Phaser.Point} the modified original vector
- */
- setMagnitude: function(magnitude) {
- return this.normalize().multiply(magnitude, magnitude);
- },
- /**
- * Alters the vector so that its length is 1, but it retains the same direction
- * @method Phaser.Point#normalize
- * @return {Phaser.Point} the modified original vector
- */
- normalize: function() {
- if(!this.isZero()) {
- var m = this.getMagnitude();
- this.x /= m;
- this.y /= m;
- }
- return this;
- },
- /**
- * Determine if this point is at 0,0
- * @method Phaser.Point#isZero
- * @return {boolean} True if this Point is 0,0, otherwise false
- */
- isZero: function() {
- return (this.x === 0 && this.y === 0);
- },
- /**
- * Returns a string representation of this object.
- * @method Phaser.Point#toString
- * @return {string} A string representation of the instance.
- */
- toString: function () {
- return '[{Point (x=' + this.x + ' y=' + this.y + ')}]';
- }
- };
- Phaser.Point.prototype.constructor = Phaser.Point;
- /**
- * Adds the coordinates of two points together to create a new point.
- * @method Phaser.Point.add
- * @param {Phaser.Point} a - The first Point object.
- * @param {Phaser.Point} b - The second Point object.
- * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
- * @return {Phaser.Point} The new Point object.
- */
- Phaser.Point.add = function (a, b, out) {
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- return out;
- };
- /**
- * Subtracts the coordinates of two points to create a new point.
- * @method Phaser.Point.subtract
- * @param {Phaser.Point} a - The first Point object.
- * @param {Phaser.Point} b - The second Point object.
- * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
- * @return {Phaser.Point} The new Point object.
- */
- Phaser.Point.subtract = function (a, b, out) {
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- out.x = a.x - b.x;
- out.y = a.y - b.y;
- return out;
- };
- /**
- * Multiplies the coordinates of two points to create a new point.
- * @method Phaser.Point.multiply
- * @param {Phaser.Point} a - The first Point object.
- * @param {Phaser.Point} b - The second Point object.
- * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
- * @return {Phaser.Point} The new Point object.
- */
- Phaser.Point.multiply = function (a, b, out) {
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- out.x = a.x * b.x;
- out.y = a.y * b.y;
- return out;
- };
- /**
- * Divides the coordinates of two points to create a new point.
- * @method Phaser.Point.divide
- * @param {Phaser.Point} a - The first Point object.
- * @param {Phaser.Point} b - The second Point object.
- * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
- * @return {Phaser.Point} The new Point object.
- */
- Phaser.Point.divide = function (a, b, out) {
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- out.x = a.x / b.x;
- out.y = a.y / b.y;
- return out;
- };
- /**
- * Determines whether the two given Point objects are equal. They are considered equal if they have the same x and y values.
- * @method Phaser.Point.equals
- * @param {Phaser.Point} a - The first Point object.
- * @param {Phaser.Point} b - The second Point object.
- * @return {boolean} A value of true if the Points are equal, otherwise false.
- */
- Phaser.Point.equals = function (a, b) {
- return (a.x == b.x && a.y == b.y);
- };
- /**
- * Returns the distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties).
- * @method Phaser.Point.distance
- * @param {object} a - The target object. Must have visible x and y properties that represent the center of the object.
- * @param {object} b - The target object. Must have visible x and y properties that represent the center of the object.
- * @param {boolean} [round] - Round the distance to the nearest integer (default false).
- * @return {number} The distance between this Point object and the destination Point object.
- */
- Phaser.Point.distance = function (a, b, round) {
- if (typeof round === "undefined") { round = false; }
- if (round)
- {
- return Phaser.Math.distanceRound(a.x, a.y, b.x, b.y);
- }
- else
- {
- return Phaser.Math.distance(a.x, a.y, b.x, b.y);
- }
- };
- /**
- * Rotates a Point around the x/y coordinates given to the desired angle.
- * @method Phaser.Point.rotate
- * @param {Phaser.Point} a - The Point object to rotate.
- * @param {number} x - The x coordinate of the anchor point
- * @param {number} y - The y coordinate of the anchor point
- * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point to.
- * @param {boolean} asDegrees - Is the given rotation in radians (false) or degrees (true)?
- * @param {number} distance - An optional distance constraint between the Point and the anchor.
- * @return {Phaser.Point} The modified point object.
- */
- Phaser.Point.rotate = function (a, x, y, angle, asDegrees, distance) {
- asDegrees = asDegrees || false;
- distance = distance || null;
- if (asDegrees)
- {
- angle = Phaser.Math.degToRad(angle);
- }
- // Get distance from origin (cx/cy) to this point
- if (distance === null)
- {
- distance = Math.sqrt(((x - a.x) * (x - a.x)) + ((y - a.y) * (y - a.y)));
- }
- return a.setTo(x + distance * Math.cos(angle), y + distance * Math.sin(angle));
- };
- /**
- * Calculates centroid (or midpoint) from an array of points. If only one point is provided, that point is returned.
- * @method Phaser.Point.centroid
- * @param {Phaser.Point[]} points - The array of one or more points.
- * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
- * @return {Phaser.Point} The new Point object.
- */
- Phaser.Point.centroid = function (points, out) {
- if (typeof out === "undefined") { out = new Phaser.Point(); }
- if (Object.prototype.toString.call(points) !== '[object Array]')
- {
- throw new Error("Phaser.Point. Parameter 'points' must be an array");
- }
- var pointslength = points.length;
- if (pointslength < 1)
- {
- throw new Error("Phaser.Point. Parameter 'points' array must not be empty");
- }
- if (pointslength === 1)
- {
- out.copyFrom(points[0]);
- return out;
- }
- for (var i = 0; i < pointslength; i++)
- {
- Phaser.Point.add(out, points[i], out);
- }
- out.divide(pointslength, pointslength);
- return out;
- };
- // Because PIXI uses its own Point, we'll replace it with ours to avoid duplicating code or confusion.
- PIXI.Point = Phaser.Point;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created.
- *
- * @class Phaser.Rectangle
- * @constructor
- * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
- * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
- * @param {number} width - The width of the Rectangle.
- * @param {number} height - The height of the Rectangle.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- Phaser.Rectangle = function (x, y, width, height) {
- x = x || 0;
- y = y || 0;
- width = width || 0;
- height = height || 0;
- /**
- * @property {number} x - The x coordinate of the top-left corner of the Rectangle.
- */
- this.x = x;
- /**
- * @property {number} y - The y coordinate of the top-left corner of the Rectangle.
- */
- this.y = y;
- /**
- * @property {number} width - The width of the Rectangle.
- */
- this.width = width;
- /**
- * @property {number} height - The height of the Rectangle.
- */
- this.height = height;
- };
- Phaser.Rectangle.prototype = {
- /**
- * Adjusts the location of the Rectangle object, as determined by its top-left corner, by the specified amounts.
- * @method Phaser.Rectangle#offset
- * @param {number} dx - Moves the x value of the Rectangle object by this amount.
- * @param {number} dy - Moves the y value of the Rectangle object by this amount.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- offset: function (dx, dy) {
- this.x += dx;
- this.y += dy;
- return this;
- },
- /**
- * Adjusts the location of the Rectangle object using a Point object as a parameter. This method is similar to the Rectangle.offset() method, except that it takes a Point object as a parameter.
- * @method Phaser.Rectangle#offsetPoint
- * @param {Phaser.Point} point - A Point object to use to offset this Rectangle object.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- offsetPoint: function (point) {
- return this.offset(point.x, point.y);
- },
- /**
- * Sets the members of Rectangle to the specified values.
- * @method Phaser.Rectangle#setTo
- * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
- * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
- * @param {number} width - The width of the Rectangle in pixels.
- * @param {number} height - The height of the Rectangle in pixels.
- * @return {Phaser.Rectangle} This Rectangle object
- */
- setTo: function (x, y, width, height) {
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- return this;
- },
- /**
- * Runs Math.floor() on both the x and y values of this Rectangle.
- * @method Phaser.Rectangle#floor
- */
- floor: function () {
- this.x = Math.floor(this.x);
- this.y = Math.floor(this.y);
- },
- /**
- * Runs Math.floor() on the x, y, width and height values of this Rectangle.
- * @method Phaser.Rectangle#floorAll
- */
- floorAll: function () {
- this.x = Math.floor(this.x);
- this.y = Math.floor(this.y);
- this.width = Math.floor(this.width);
- this.height = Math.floor(this.height);
- },
- /**
- * Copies the x, y, width and height properties from any given object to this Rectangle.
- * @method Phaser.Rectangle#copyFrom
- * @param {any} source - The object to copy from.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- copyFrom: function (source) {
- return this.setTo(source.x, source.y, source.width, source.height);
- },
- /**
- * Copies the x, y, width and height properties from this Rectangle to any given object.
- * @method Phaser.Rectangle#copyTo
- * @param {any} source - The object to copy to.
- * @return {object} This object.
- */
- copyTo: function (dest) {
- dest.x = this.x;
- dest.y = this.y;
- dest.width = this.width;
- dest.height = this.height;
- return dest;
- },
- /**
- * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value.
- * @method Phaser.Rectangle#inflate
- * @param {number} dx - The amount to be added to the left side of the Rectangle.
- * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- inflate: function (dx, dy) {
- return Phaser.Rectangle.inflate(this, dx, dy);
- },
- /**
- * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
- * @method Phaser.Rectangle#size
- * @param {Phaser.Point} [output] - Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned.
- * @return {Phaser.Point} The size of the Rectangle object.
- */
- size: function (output) {
- return Phaser.Rectangle.size(this, output);
- },
- /**
- * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
- * @method Phaser.Rectangle#clone
- * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle}
- */
- clone: function (output) {
- return Phaser.Rectangle.clone(this, output);
- },
- /**
- * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
- * @method Phaser.Rectangle#contains
- * @param {number} x - The x coordinate of the point to test.
- * @param {number} y - The y coordinate of the point to test.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- contains: function (x, y) {
- return Phaser.Rectangle.contains(this, x, y);
- },
- /**
- * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
- * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
- * @method Phaser.Rectangle#containsRect
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- containsRect: function (b) {
- return Phaser.Rectangle.containsRect(this, b);
- },
- /**
- * Determines whether the two Rectangles are equal.
- * This method compares the x, y, width and height properties of each Rectangle.
- * @method Phaser.Rectangle#equals
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @return {boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false.
- */
- equals: function (b) {
- return Phaser.Rectangle.equals(this, b);
- },
- /**
- * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0.
- * @method Phaser.Rectangle#intersection
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @param {Phaser.Rectangle} out - Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0.
- */
- intersection: function (b, out) {
- return Phaser.Rectangle.intersection(this, b, out);
- },
- /**
- * Determines whether the two Rectangles intersect with each other.
- * This method checks the x, y, width, and height properties of the Rectangles.
- * @method Phaser.Rectangle#intersects
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0.
- * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
- */
- intersects: function (b, tolerance) {
- return Phaser.Rectangle.intersects(this, b, tolerance);
- },
- /**
- * Determines whether the object specified intersects (overlaps) with the given values.
- * @method Phaser.Rectangle#intersectsRaw
- * @param {number} left - Description.
- * @param {number} right - Description.
- * @param {number} top - Description.
- * @param {number} bottomt - Description.
- * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
- * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
- */
- intersectsRaw: function (left, right, top, bottom, tolerance) {
- return Phaser.Rectangle.intersectsRaw(this, left, right, top, bottom, tolerance);
- },
- /**
- * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
- * @method Phaser.Rectangle#union
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @param {Phaser.Rectangle} [out] - Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
- */
- union: function (b, out) {
- return Phaser.Rectangle.union(this, b, out);
- },
- /**
- * Returns a string representation of this object.
- * @method Phaser.Rectangle#toString
- * @return {string} A string representation of the instance.
- */
- toString: function () {
- return "[{Rectangle (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + " empty=" + this.empty + ")}]";
- }
- };
- /**
- * @name Phaser.Rectangle#halfWidth
- * @property {number} halfWidth - Half of the width of the Rectangle.
- * @readonly
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "halfWidth", {
- get: function () {
- return Math.round(this.width / 2);
- }
- });
- /**
- * @name Phaser.Rectangle#halfHeight
- * @property {number} halfHeight - Half of the height of the Rectangle.
- * @readonly
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "halfHeight", {
- get: function () {
- return Math.round(this.height / 2);
- }
- });
- /**
- * The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
- * @name Phaser.Rectangle#bottom
- * @property {number} bottom - The sum of the y and height properties.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "bottom", {
- get: function () {
- return this.y + this.height;
- },
- set: function (value) {
- if (value <= this.y) {
- this.height = 0;
- } else {
- this.height = (this.y - value);
- }
- }
- });
- /**
- * The location of the Rectangles bottom right corner as a Point object.
- * @name Phaser.Rectangle#bottom
- * @property {Phaser.Point} bottomRight - Gets or sets the location of the Rectangles bottom right corner as a Point object.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "bottomRight", {
- get: function () {
- return new Phaser.Point(this.right, this.bottom);
- },
- set: function (value) {
- this.right = value.x;
- this.bottom = value.y;
- }
- });
- /**
- * The x coordinate of the left of the Rectangle. Changing the left property of a Rectangle object has no effect on the y and height properties. However it does affect the width property, whereas changing the x value does not affect the width property.
- * @name Phaser.Rectangle#left
- * @property {number} left - The x coordinate of the left of the Rectangle.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "left", {
- get: function () {
- return this.x;
- },
- set: function (value) {
- if (value >= this.right) {
- this.width = 0;
- } else {
- this.width = this.right - value;
- }
- this.x = value;
- }
- });
- /**
- * The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties, however it does affect the width property.
- * @name Phaser.Rectangle#right
- * @property {number} right - The sum of the x and width properties.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "right", {
- get: function () {
- return this.x + this.width;
- },
- set: function (value) {
- if (value <= this.x) {
- this.width = 0;
- } else {
- this.width = this.x + value;
- }
- }
- });
- /**
- * The volume of the Rectangle derived from width * height.
- * @name Phaser.Rectangle#volume
- * @property {number} volume - The volume of the Rectangle derived from width * height.
- * @readonly
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "volume", {
- get: function () {
- return this.width * this.height;
- }
- });
- /**
- * The perimeter size of the Rectangle. This is the sum of all 4 sides.
- * @name Phaser.Rectangle#perimeter
- * @property {number} perimeter - The perimeter size of the Rectangle. This is the sum of all 4 sides.
- * @readonly
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "perimeter", {
- get: function () {
- return (this.width * 2) + (this.height * 2);
- }
- });
- /**
- * The x coordinate of the center of the Rectangle.
- * @name Phaser.Rectangle#centerX
- * @property {number} centerX - The x coordinate of the center of the Rectangle.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "centerX", {
- get: function () {
- return this.x + this.halfWidth;
- },
- set: function (value) {
- this.x = value - this.halfWidth;
- }
- });
- /**
- * The y coordinate of the center of the Rectangle.
- * @name Phaser.Rectangle#centerY
- * @property {number} centerY - The y coordinate of the center of the Rectangle.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "centerY", {
- get: function () {
- return this.y + this.halfHeight;
- },
- set: function (value) {
- this.y = value - this.halfHeight;
- }
- });
- /**
- * The y coordinate of the top of the Rectangle. Changing the top property of a Rectangle object has no effect on the x and width properties.
- * However it does affect the height property, whereas changing the y value does not affect the height property.
- * @name Phaser.Rectangle#top
- * @property {number} top - The y coordinate of the top of the Rectangle.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "top", {
- get: function () {
- return this.y;
- },
- set: function (value) {
- if (value >= this.bottom) {
- this.height = 0;
- this.y = value;
- } else {
- this.height = (this.bottom - value);
- }
- }
- });
- /**
- * The location of the Rectangles top left corner as a Point object.
- * @name Phaser.Rectangle#topLeft
- * @property {Phaser.Point} topLeft - The location of the Rectangles top left corner as a Point object.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "topLeft", {
- get: function () {
- return new Phaser.Point(this.x, this.y);
- },
- set: function (value) {
- this.x = value.x;
- this.y = value.y;
- }
- });
- /**
- * Determines whether or not this Rectangle object is empty. A Rectangle object is empty if its width or height is less than or equal to 0.
- * If set to true then all of the Rectangle properties are set to 0.
- * @name Phaser.Rectangle#empty
- * @property {boolean} empty - Gets or sets the Rectangles empty state.
- */
- Object.defineProperty(Phaser.Rectangle.prototype, "empty", {
- get: function () {
- return (!this.width || !this.height);
- },
- set: function (value) {
- if (value === true)
- {
- this.setTo(0, 0, 0, 0);
- }
- }
- });
- Phaser.Rectangle.prototype.constructor = Phaser.Rectangle;
- /**
- * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value.
- * @method Phaser.Rectangle.inflate
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {number} dx - The amount to be added to the left side of the Rectangle.
- * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
- * @return {Phaser.Rectangle} This Rectangle object.
- */
- Phaser.Rectangle.inflate = function (a, dx, dy) {
- a.x -= dx;
- a.width += 2 * dx;
- a.y -= dy;
- a.height += 2 * dy;
- return a;
- };
- /**
- * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter.
- * @method Phaser.Rectangle.inflatePoint
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {Phaser.Point} point - The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object.
- * @return {Phaser.Rectangle} The Rectangle object.
- */
- Phaser.Rectangle.inflatePoint = function (a, point) {
- return Phaser.Rectangle.inflate(a, point.x, point.y);
- };
- /**
- * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
- * @method Phaser.Rectangle.size
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {Phaser.Point} [output] - Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned.
- * @return {Phaser.Point} The size of the Rectangle object
- */
- Phaser.Rectangle.size = function (a, output) {
- if (typeof output === "undefined")
- {
- output = new Phaser.Point(a.width, a.height);
- }
- else
- {
- output.setTo(a.width, a.height);
- }
- return output;
- };
- /**
- * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
- * @method Phaser.Rectangle.clone
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle}
- */
- Phaser.Rectangle.clone = function (a, output) {
- if (typeof output === "undefined")
- {
- output = new Phaser.Rectangle(a.x, a.y, a.width, a.height);
- }
- else
- {
- output.setTo(a.x, a.y, a.width, a.height);
- }
- return output;
- };
- /**
- * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
- * @method Phaser.Rectangle.contains
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {number} x - The x coordinate of the point to test.
- * @param {number} y - The y coordinate of the point to test.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- Phaser.Rectangle.contains = function (a, x, y) {
- if (a.width <= 0 || a.height <= 0)
- {
- return false;
- }
- return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom);
- };
- /**
- * Determines whether the specified coordinates are contained within the region defined by the given raw values.
- * @method Phaser.Rectangle.containsRaw
- * @param {number} rx - The x coordinate of the top left of the area.
- * @param {number} ry - The y coordinate of the top left of the area.
- * @param {number} rw - The width of the area.
- * @param {number} rh - The height of the area.
- * @param {number} x - The x coordinate of the point to test.
- * @param {number} y - The y coordinate of the point to test.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- Phaser.Rectangle.containsRaw = function (rx, ry, rw, rh, x, y) {
- return (x >= rx && x <= (rx + rw) && y >= ry && y <= (ry + rh));
- };
- /**
- * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter.
- * @method Phaser.Rectangle.containsPoint
- * @param {Phaser.Rectangle} a - The Rectangle object.
- * @param {Phaser.Point} point - The point object being checked. Can be Point or any object with .x and .y values.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- Phaser.Rectangle.containsPoint = function (a, point) {
- return Phaser.Rectangle.contains(a, point.x, point.y);
- };
- /**
- * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
- * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
- * @method Phaser.Rectangle.containsRect
- * @param {Phaser.Rectangle} a - The first Rectangle object.
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
- */
- Phaser.Rectangle.containsRect = function (a, b) {
- // If the given rect has a larger volume than this one then it can never contain it
- if (a.volume > b.volume)
- {
- return false;
- }
- return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom);
- };
- /**
- * Determines whether the two Rectangles are equal.
- * This method compares the x, y, width and height properties of each Rectangle.
- * @method Phaser.Rectangle.equals
- * @param {Phaser.Rectangle} a - The first Rectangle object.
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @return {boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false.
- */
- Phaser.Rectangle.equals = function (a, b) {
- return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height);
- };
- /**
- * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0.
- * @method Phaser.Rectangle.intersection
- * @param {Phaser.Rectangle} a - The first Rectangle object.
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0.
- */
- Phaser.Rectangle.intersection = function (a, b, output) {
- if (typeof output === "undefined")
- {
- output = new Phaser.Rectangle();
- }
- if (Phaser.Rectangle.intersects(a, b))
- {
- output.x = Math.max(a.x, b.x);
- output.y = Math.max(a.y, b.y);
- output.width = Math.min(a.right, b.right) - output.x;
- output.height = Math.min(a.bottom, b.bottom) - output.y;
- }
- return output;
- };
- /**
- * Determines whether the two Rectangles intersect with each other.
- * This method checks the x, y, width, and height properties of the Rectangles.
- * @method Phaser.Rectangle.intersects
- * @param {Phaser.Rectangle} a - The first Rectangle object.
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
- */
- Phaser.Rectangle.intersects = function (a, b) {
- if (a.width <= 0 || a.height <= 0 || b.width <= 0 || b.height <= 0)
- {
- return false;
- }
- return !(a.right < b.x || a.bottom < b.y || a.x > b.right || a.y > b.bottom);
- };
- /**
- * Determines whether the object specified intersects (overlaps) with the given values.
- * @method Phaser.Rectangle.intersectsRaw
- * @param {number} left - Description.
- * @param {number} right - Description.
- * @param {number} top - Description.
- * @param {number} bottom - Description.
- * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
- * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
- */
- Phaser.Rectangle.intersectsRaw = function (a, left, right, top, bottom, tolerance) {
- if (typeof tolerance === "undefined") { tolerance = 0; }
- return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance);
- };
- /**
- * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
- * @method Phaser.Rectangle.union
- * @param {Phaser.Rectangle} a - The first Rectangle object.
- * @param {Phaser.Rectangle} b - The second Rectangle object.
- * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
- * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
- */
- Phaser.Rectangle.union = function (a, b, output) {
- if (typeof output === "undefined")
- {
- output = new Phaser.Rectangle();
- }
- return output.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right) - Math.min(a.left, b.left), Math.max(a.bottom, b.bottom) - Math.min(a.top, b.top));
- };
- // Because PIXI uses its own Rectangle, we'll replace it with ours to avoid duplicating code or confusion.
- PIXI.Rectangle = Phaser.Rectangle;
- PIXI.EmptyRectangle = new Phaser.Rectangle(0, 0, 0, 0);
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a new Line object with a start and an end point.
- * @class Line
- * @classdesc Phaser - Line
- * @constructor
- * @param {number} [x1=0] - The x coordinate of the start of the line.
- * @param {number} [y1=0] - The y coordinate of the start of the line.
- * @param {number} [x2=0] - The x coordinate of the end of the line.
- * @param {number} [y2=0] - The y coordinate of the end of the line.
- * @return {Phaser.Line} This line object
- */
- Phaser.Line = function (x1, y1, x2, y2) {
- x1 = x1 || 0;
- y1 = y1 || 0;
- x2 = x2 || 0;
- y2 = y2 || 0;
- /**
- * @property {Phaser.Point} start - The start point of the line.
- */
- this.start = new Phaser.Point(x1, y1);
- /**
- * @property {Phaser.Point} end - The end point of the line.
- */
- this.end = new Phaser.Point(x2, y2);
- };
- Phaser.Line.prototype = {
- /**
- * Sets the components of the Line to the specified values.
- * @method Phaser.Line#setTo
- * @param {number} [x1=0] - The x coordinate of the start of the line.
- * @param {number} [y1=0] - The y coordinate of the start of the line.
- * @param {number} [x2=0] - The x coordinate of the end of the line.
- * @param {number} [y2=0] - The y coordinate of the end of the line.
- * @return {Phaser.Line} This line object
- */
- setTo: function (x1, y1, x2, y2) {
- this.start.setTo(x1, y1);
- this.end.setTo(x2, y2);
- return this;
- },
- /**
- * Sets the line to match the x/y coordinates of the two given sprites.
- * Can optionally be calculated from their center coordinates.
- * @method Phaser.Line#fromSprite
- * @param {Phaser.Sprite} startSprite - The coordinates of this Sprite will be set to the Line.start point.
- * @param {Phaser.Sprite} endSprite - The coordinates of this Sprite will be set to the Line.start point.
- * @param {boolean} [useCenter=false] - If true it will use startSprite.center.x, if false startSprite.x. Note that Sprites don't have a center property by default, so only enable if you've over-ridden your Sprite with a custom class.
- * @return {Phaser.Line} This line object
- */
- fromSprite: function (startSprite, endSprite, useCenter) {
- if (typeof useCenter === 'undefined') { useCenter = false; }
- if (useCenter)
- {
- return this.setTo(startSprite.center.x, startSprite.center.y, endSprite.center.x, endSprite.center.y);
- }
- else
- {
- return this.setTo(startSprite.x, startSprite.y, endSprite.x, endSprite.y);
- }
- },
- /**
- * Checks for intersection between this line and another Line.
- * If asSegment is true it will check for segment intersection. If asSegment is false it will check for line intersection.
- * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
- *
- * @method Phaser.Line#intersects
- * @param {Phaser.Line} line - The line to check against this one.
- * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
- * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
- * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
- */
- intersects: function (line, asSegment, result) {
- return Phaser.Line.intersectsPoints(this.start, this.end, line.start, line.end, asSegment, result);
- },
- /**
- * Tests if the given coordinates fall on this line. See pointOnSegment to test against just the line segment.
- * @method Phaser.Line#pointOnLine
- * @param {number} x - The line to check against this one.
- * @param {number} y - The line to check against this one.
- * @return {boolean} True if the point is on the line, false if not.
- */
- pointOnLine: function (x, y) {
- return ((x - this.start.x) * (this.end.y - this.end.y) === (this.end.x - this.start.x) * (y - this.end.y));
- },
- /**
- * Tests if the given coordinates fall on this line and within the segment. See pointOnLine to test against just the line.
- * @method Phaser.Line#pointOnSegment
- * @param {number} x - The line to check against this one.
- * @param {number} y - The line to check against this one.
- * @return {boolean} True if the point is on the line and segment, false if not.
- */
- pointOnSegment: function (x, y) {
- var xMin = Math.min(this.start.x, this.end.x);
- var xMax = Math.max(this.start.x, this.end.x);
- var yMin = Math.min(this.start.y, this.end.y);
- var yMax = Math.max(this.start.y, this.end.y);
- return (this.pointOnLine(x, y) && (x >= xMin && x <= xMax) && (y >= yMin && y <= yMax));
- },
- /**
- * Using Bresenham's line algorithm this will return an array of all coordinates on this line.
- * The start and end points are rounded before this runs as the algorithm works on integers.
- *
- * @method Phaser.Line#coordinatesOnLine
- * @param {number} [stepRate=1] - How many steps will we return? 1 = every coordinate on the line, 2 = every other coordinate, etc.
- * @param {array} [results] - The array to store the results in. If not provided a new one will be generated.
- * @return {array} An array of coordinates.
- */
- coordinatesOnLine: function (stepRate, results) {
- if (typeof stepRate === 'undefined') { stepRate = 1; }
- if (typeof results === 'undefined') { results = []; }
- var x1 = Math.round(this.start.x);
- var y1 = Math.round(this.start.y);
- var x2 = Math.round(this.end.x);
- var y2 = Math.round(this.end.y);
- var dx = Math.abs(x2 - x1);
- var dy = Math.abs(y2 - y1);
- var sx = (x1 < x2) ? 1 : -1;
- var sy = (y1 < y2) ? 1 : -1;
- var err = dx - dy;
- results.push([x1, y1]);
- var i = 1;
- while (!((x1 == x2) && (y1 == y2)))
- {
- var e2 = err << 1;
- if (e2 > -dy)
- {
- err -= dy;
- x1 += sx;
- }
- if (e2 < dx)
- {
- err += dx;
- y1 += sy;
- }
- if (i % stepRate === 0)
- {
- results.push([x1, y1]);
- }
- i++;
- }
- return results;
- }
- };
- /**
- * @name Phaser.Line#length
- * @property {number} length - Gets the length of the line segment.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "length", {
- get: function () {
- return Math.sqrt((this.end.x - this.start.x) * (this.end.x - this.start.x) + (this.end.y - this.start.y) * (this.end.y - this.start.y));
- }
- });
- /**
- * @name Phaser.Line#angle
- * @property {number} angle - Gets the angle of the line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "angle", {
- get: function () {
- return Math.atan2(this.end.x - this.start.x, this.end.y - this.start.y);
- }
- });
- /**
- * @name Phaser.Line#slope
- * @property {number} slope - Gets the slope of the line (y/x).
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "slope", {
- get: function () {
- return (this.end.y - this.start.y) / (this.end.x - this.start.x);
- }
- });
- /**
- * @name Phaser.Line#perpSlope
- * @property {number} perpSlope - Gets the perpendicular slope of the line (x/y).
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "perpSlope", {
- get: function () {
- return -((this.end.x - this.start.x) / (this.end.y - this.start.y));
- }
- });
- /**
- * @name Phaser.Line#x
- * @property {number} x - Gets the x coordinate of the top left of the bounds around this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "x", {
- get: function () {
- return Math.min(this.start.x, this.end.x);
- }
- });
- /**
- * @name Phaser.Line#y
- * @property {number} y - Gets the y coordinate of the top left of the bounds around this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "y", {
- get: function () {
- return Math.min(this.start.y, this.end.y);
- }
- });
- /**
- * @name Phaser.Line#left
- * @property {number} left - Gets the left-most point of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "left", {
- get: function () {
- return Math.min(this.start.x, this.end.x);
- }
- });
- /**
- * @name Phaser.Line#right
- * @property {number} right - Gets the right-most point of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "right", {
- get: function () {
- return Math.max(this.start.x, this.end.x);
- }
- });
- /**
- * @name Phaser.Line#top
- * @property {number} top - Gets the top-most point of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "top", {
- get: function () {
- return Math.min(this.start.y, this.end.y);
- }
- });
- /**
- * @name Phaser.Line#bottom
- * @property {number} bottom - Gets the bottom-most point of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "bottom", {
- get: function () {
- return Math.max(this.start.y, this.end.y);
- }
- });
- /**
- * @name Phaser.Line#width
- * @property {number} width - Gets the width of this bounds of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "width", {
- get: function () {
- return Math.abs(this.start.x - this.end.x);
- }
- });
- /**
- * @name Phaser.Line#height
- * @property {number} height - Gets the height of this bounds of this line.
- * @readonly
- */
- Object.defineProperty(Phaser.Line.prototype, "height", {
- get: function () {
- return Math.abs(this.start.y - this.end.y);
- }
- });
- /**
- * Checks for intersection between two lines as defined by the given start and end points.
- * If asSegment is true it will check for line segment intersection. If asSegment is false it will check for line intersection.
- * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
- * Adapted from code by Keith Hair
- *
- * @method Phaser.Line.intersectsPoints
- * @param {Phaser.Point} a - The start of the first Line to be checked.
- * @param {Phaser.Point} b - The end of the first line to be checked.
- * @param {Phaser.Point} e - The start of the second Line to be checked.
- * @param {Phaser.Point} f - The end of the second line to be checked.
- * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
- * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
- * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
- */
- Phaser.Line.intersectsPoints = function (a, b, e, f, asSegment, result) {
- if (typeof asSegment === 'undefined') { asSegment = true; }
- if (typeof result === 'undefined') { result = new Phaser.Point(); }
- var a1 = b.y - a.y;
- var a2 = f.y - e.y;
- var b1 = a.x - b.x;
- var b2 = e.x - f.x;
- var c1 = (b.x * a.y) - (a.x * b.y);
- var c2 = (f.x * e.y) - (e.x * f.y);
- var denom = (a1 * b2) - (a2 * b1);
- if (denom === 0)
- {
- return null;
- }
- result.x = ((b1 * c2) - (b2 * c1)) / denom;
- result.y = ((a2 * c1) - (a1 * c2)) / denom;
- if (asSegment)
- {
- if (Math.pow((result.x - b.x) + (result.y - b.y), 2) > Math.pow((a.x - b.x) + (a.y - b.y), 2))
- {
- return null;
- }
- if (Math.pow((result.x - a.x) + (result.y - a.y), 2) > Math.pow((a.x - b.x) + (a.y - b.y), 2))
- {
- return null;
- }
- if (Math.pow((result.x - f.x) + (result.y - f.y), 2) > Math.pow((e.x - f.x) + (e.y - f.y), 2))
- {
- return null;
- }
- if (Math.pow((result.x - e.x) + (result.y - e.y), 2) > Math.pow((e.x - f.x) + (e.y - f.y), 2))
- {
- return null;
- }
- }
- return result;
- };
- /**
- * Checks for intersection between two lines.
- * If asSegment is true it will check for segment intersection.
- * If asSegment is false it will check for line intersection.
- * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
- * Adapted from code by Keith Hair
- *
- * @method Phaser.Line.intersects
- * @param {Phaser.Line} a - The first Line to be checked.
- * @param {Phaser.Line} b - The second Line to be checked.
- * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
- * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
- * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
- */
- Phaser.Line.intersects = function (a, b, asSegment, result) {
- return Phaser.Line.intersectsPoints(a.start, a.end, b.start, b.end, asSegment, result);
- };
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @author Chad Engler <chad@pantherdev.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a Ellipse object. A curve on a plane surrounding two focal points.
- * @class Ellipse
- * @classdesc Phaser - Ellipse
- * @constructor
- * @param {number} [x=0] - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
- * @param {number} [y=0] - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
- * @param {number} [width=0] - The overall width of this ellipse.
- * @param {number} [height=0] - The overall height of this ellipse.
- * @return {Phaser.Ellipse} This Ellipse object
- */
- Phaser.Ellipse = function (x, y, width, height) {
- this.type = Phaser.ELLIPSE;
- x = x || 0;
- y = y || 0;
- width = width || 0;
- height = height || 0;
- /**
- * @property {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
- */
- this.x = x;
- /**
- * @property {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
- */
- this.y = y;
- /**
- * @property {number} width - The overall width of this ellipse.
- */
- this.width = width;
- /**
- * @property {number} height - The overall height of this ellipse.
- */
- this.height = height;
- };
- Phaser.Ellipse.prototype = {
- /**
- * Sets the members of the Ellipse to the specified values.
- * @method Phaser.Ellipse#setTo
- * @param {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
- * @param {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
- * @param {number} width - The overall width of this ellipse.
- * @param {number} height - The overall height of this ellipse.
- * @return {Phaser.Ellipse} This Ellipse object.
- */
- setTo: function (x, y, width, height) {
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- return this;
- },
- /**
- * Copies the x, y, width and height properties from any given object to this Ellipse.
- * @method Phaser.Ellipse#copyFrom
- * @param {any} source - The object to copy from.
- * @return {Phaser.Ellipse} This Ellipse object.
- */
- copyFrom: function (source) {
- return this.setTo(source.x, source.y, source.width, source.height);
- },
- /**
- * Copies the x, y and diameter properties from this Circle to any given object.
- * @method Phaser.Ellipse#copyTo
- * @param {any} dest - The object to copy to.
- * @return {Object} This dest object.
- */
- copyTo: function(dest) {
- dest.x = this.x;
- dest.y = this.y;
- dest.width = this.width;
- dest.height = this.height;
- return dest;
- },
- /**
- * Returns a new Ellipse object with the same values for the x, y, width, and height properties as this Ellipse object.
- * @method Phaser.Ellipse#clone
- * @param {Phaser.Ellipse} out - Optional Ellipse object. If given the values will be set into the object, otherwise a brand new Ellipse object will be created and returned.
- * @return {Phaser.Ellipse} The cloned Ellipse object.
- */
- clone: function(out) {
- if (typeof out === "undefined")
- {
- out = new Phaser.Ellipse(this.x, this.y, this.width, this.height);
- }
- else
- {
- out.setTo(this.x, this.y, this.width, this.height);
- }
- return out;
- },
- /**
- * Return true if the given x/y coordinates are within this Ellipse object.
- * @method Phaser.Ellipse#contains
- * @param {number} x - The X value of the coordinate to test.
- * @param {number} y - The Y value of the coordinate to test.
- * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
- */
- contains: function (x, y) {
- return Phaser.Ellipse.contains(this, x, y);
- },
- /**
- * Returns a string representation of this object.
- * @method Phaser.Ellipse#toString
- * @return {string} A string representation of the instance.
- */
- toString: function () {
- return "[{Phaser.Ellipse (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + ")}]";
- }
- };
- Phaser.Ellipse.prototype.constructor = Phaser.Ellipse;
- /**
- * The left coordinate of the Ellipse. The same as the X coordinate.
- * @name Phaser.Ellipse#left
- * @propety {number} left - Gets or sets the value of the leftmost point of the ellipse.
- */
- Object.defineProperty(Phaser.Ellipse.prototype, "left", {
- get: function () {
- return this.x;
- },
- set: function (value) {
- this.x = value;
- }
- });
- /**
- * The x coordinate of the rightmost point of the Ellipse. Changing the right property of an Ellipse object has no effect on the x property, but does adjust the width.
- * @name Phaser.Ellipse#right
- * @property {number} right - Gets or sets the value of the rightmost point of the ellipse.
- */
- Object.defineProperty(Phaser.Ellipse.prototype, "right", {
- get: function () {
- return this.x + this.width;
- },
- set: function (value) {
- if (value < this.x)
- {
- this.width = 0;
- }
- else
- {
- this.width = this.x + value;
- }
- }
- });
- /**
- * The top of the Ellipse. The same as its y property.
- * @name Phaser.Ellipse#top
- * @property {number} top - Gets or sets the top of the ellipse.
- */
- Object.defineProperty(Phaser.Ellipse.prototype, "top", {
- get: function () {
- return this.y;
- },
- set: function (value) {
- this.y = value;
- }
- });
- /**
- * The sum of the y and height properties. Changing the bottom property of an Ellipse doesn't adjust the y property, but does change the height.
- * @name Phaser.Ellipse#bottom
- * @property {number} bottom - Gets or sets the bottom of the ellipse.
- */
- Object.defineProperty(Phaser.Ellipse.prototype, "bottom", {
- get: function () {
- return this.y + this.height;
- },
- set: function (value) {
- if (value < this.y)
- {
- this.height = 0;
- }
- else
- {
- this.height = this.y + value;
- }
- }
- });
- /**
- * Determines whether or not this Ellipse object is empty. Will return a value of true if the Ellipse objects dimensions are less than or equal to 0; otherwise false.
- * If set to true it will reset all of the Ellipse objects properties to 0. An Ellipse object is empty if its width or height is less than or equal to 0.
- * @name Phaser.Ellipse#empty
- * @property {boolean} empty - Gets or sets the empty state of the ellipse.
- */
- Object.defineProperty(Phaser.Ellipse.prototype, "empty", {
- get: function () {
- return (this.width === 0 || this.height === 0);
- },
- set: function (value) {
- if (value === true)
- {
- this.setTo(0, 0, 0, 0);
- }
- }
- });
- /**
- * Return true if the given x/y coordinates are within the Ellipse object.
- * @method Phaser.Ellipse.contains
- * @param {Phaser.Ellipse} a - The Ellipse to be checked.
- * @param {number} x - The X value of the coordinate to test.
- * @param {number} y - The Y value of the coordinate to test.
- * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
- */
- Phaser.Ellipse.contains = function (a, x, y) {
- if (a.width <= 0 || a.height <= 0)
- {
- return false;
- }
- // Normalize the coords to an ellipse with center 0,0 and a radius of 0.5
- var normx = ((x - a.x) / a.width) - 0.5;
- var normy = ((y - a.y) / a.height) - 0.5;
- normx *= normx;
- normy *= normy;
- return (normx + normy < 0.25);
- };
- /**
- * Returns the framing rectangle of the ellipse as a Phaser.Rectangle object.
- *
- * @method Phaser.Ellipse.getBounds
- * @return {Phaser.Rectangle} The framing rectangle
- */
- Phaser.Ellipse.prototype.getBounds = function() {
- return new Phaser.Rectangle(this.x, this.y, this.width, this.height);
- };
- // Because PIXI uses its own Ellipse, we'll replace it with ours to avoid duplicating code or confusion.
- PIXI.Ellipse = Phaser.Ellipse;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @author Adrien Brault <adrien.brault@gmail.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Creates a new Polygon. You have to provide a list of points.
- * 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 Phaser.Polygon(new Phaser.Point(), new Phaser.Point(), ...)`, or the
- * arguments passed can be flat x,y values e.g. `new Phaser.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
- *
- * @class Phaser.Polygon
- * @classdesc The polygon represents a list of orderded points in space
- * @constructor
- * @param {Array<Phaser.Point>|Array<number>} points - The array of Points.
- */
- Phaser.Polygon = function (points) {
- /**
- * @property {number} type - The base object type.
- */
- this.type = Phaser.POLYGON;
- //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, len = points.length; i < len; i += 2)
- {
- p.push(new Phaser.Point(points[i], points[i + 1]));
- }
- points = p;
- }
- /**
- * @property {array<Phaser.Point>|array<number>} points - The array of Points.
- */
- this.points = points;
- };
- Phaser.Polygon.prototype = {
- /**
- * Creates a clone of this polygon.
- *
- * @method Phaser.Polygon#clone
- * @return {Phaser.Polygon} A copy of the polygon.
- */
- clone: function () {
- var points = [];
- for (var i=0; i < this.points.length; i++)
- {
- points.push(this.points[i].clone());
- }
- return new Phaser.Polygon(points);
- },
- /**
- * Checks whether the x and y coordinates are contained within this polygon.
- *
- * @method Phaser.Polygon#contains
- * @param {number} x - The X value of the coordinate to test.
- * @param {number} y - The Y value of the coordinate to test.
- * @return {boolean} True if the coordinates are within this polygon, otherwise false.
- */
- contains: function (x, y) {
- var inside = false;
- // use some raycasting to test hits https://github.com/substack/point-in-polygon/blob/master/index.js
- for (var i = 0, j = this.points.length - 1; i < this.points.length; j = i++)
- {
- var xi = this.points[i].x;
- var yi = this.points[i].y;
- var xj = this.points[j].x;
- var yj = this.points[j].y;
- var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
- if (intersect)
- {
- inside = true;
- }
- }
- return inside;
- }
- };
- Phaser.Polygon.prototype.constructor = Phaser.Polygon;
- // Because PIXI uses its own Polygon, we'll replace it with ours to avoid duplicating code or confusion.
- PIXI.Polygon = Phaser.Polygon;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * A Camera is your view into the game world. It has a position and size and renders only those objects within its field of view.
- * The game automatically creates a single Stage sized camera on boot. Move the camera around the world with Phaser.Camera.x/y
- *
- * @class Phaser.Camera
- * @constructor
- * @param {Phaser.Game} game - Game reference to the currently running game.
- * @param {number} id - Not being used at the moment, will be when Phaser supports multiple camera
- * @param {number} x - Position of the camera on the X axis
- * @param {number} y - Position of the camera on the Y axis
- * @param {number} width - The width of the view rectangle
- * @param {number} height - The height of the view rectangle
- */
- Phaser.Camera = function (game, id, x, y, width, height) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running Game.
- */
- this.game = game;
- /**
- * @property {Phaser.World} world - A reference to the game world.
- */
- this.world = game.world;
- /**
- * @property {number} id - Reserved for future multiple camera set-ups.
- * @default
- */
- this.id = 0;
- /**
- * Camera view.
- * The view into the world we wish to render (by default the game dimensions).
- * The x/y values are in world coordinates, not screen coordinates, the width/height is how many pixels to render.
- * Objects outside of this view are not rendered if set to camera cull.
- * @property {Phaser.Rectangle} view
- */
- this.view = new Phaser.Rectangle(x, y, width, height);
- /**
- * @property {Phaser.Rectangle} screenView - Used by Sprites to work out Camera culling.
- */
- this.screenView = new Phaser.Rectangle(x, y, width, height);
- /**
- * The Camera is bound to this Rectangle and cannot move outside of it. By default it is enabled and set to the size of the World.
- * The Rectangle can be located anywhere in the world and updated as often as you like. If you don't wish the Camera to be bound
- * at all then set this to null. The values can be anything and are in World coordinates, with 0,0 being the center of the world.
- * @property {Phaser.Rectangle} bounds - The Rectangle in which the Camera is bounded. Set to null to allow for movement anywhere.
- */
- this.bounds = new Phaser.Rectangle(x, y, width, height);
- /**
- * @property {Phaser.Rectangle} deadzone - Moving inside this Rectangle will not cause camera moving.
- */
- this.deadzone = null;
- /**
- * @property {boolean} visible - Whether this camera is visible or not.
- * @default
- */
- this.visible = true;
- /**
- * @property {boolean} atLimit - Whether this camera is flush with the World Bounds or not.
- */
- this.atLimit = { x: false, y: false };
- /**
- * @property {Phaser.Sprite} target - If the camera is tracking a Sprite, this is a reference to it, otherwise null.
- * @default
- */
- this.target = null;
- /**
- * @property {number} edge - Edge property.
- * @private
- * @default
- */
- this._edge = 0;
- /**
- * @property {PIXI.DisplayObject} displayObject - The display object to which all game objects are added. Set by World.boot
- */
- this.displayObject = null;
- /**
- * @property {Phaser.Point} scale - The scale of the display object to which all game objects are added. Set by World.boot
- */
- this.scale = null;
- };
- /**
- * @constant
- * @type {number}
- */
- Phaser.Camera.FOLLOW_LOCKON = 0;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Camera.FOLLOW_PLATFORMER = 1;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Camera.FOLLOW_TOPDOWN = 2;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Camera.FOLLOW_TOPDOWN_TIGHT = 3;
- Phaser.Camera.prototype = {
- /**
- * Tells this camera which sprite to follow.
- * @method Phaser.Camera#follow
- * @param {Phaser.Sprite|Phaser.Image|Phaser.Text} target - The object you want the camera to track. Set to null to not follow anything.
- * @param {number} [style] - Leverage one of the existing "deadzone" presets. If you use a custom deadzone, ignore this parameter and manually specify the deadzone after calling follow().
- */
- follow: function (target, style) {
- if (typeof style === "undefined") { style = Phaser.Camera.FOLLOW_LOCKON; }
- this.target = target;
- var helper;
- switch (style) {
- case Phaser.Camera.FOLLOW_PLATFORMER:
- var w = this.width / 8;
- var h = this.height / 3;
- this.deadzone = new Phaser.Rectangle((this.width - w) / 2, (this.height - h) / 2 - h * 0.25, w, h);
- break;
- case Phaser.Camera.FOLLOW_TOPDOWN:
- helper = Math.max(this.width, this.height) / 4;
- this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
- break;
- case Phaser.Camera.FOLLOW_TOPDOWN_TIGHT:
- helper = Math.max(this.width, this.height) / 8;
- this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
- break;
- case Phaser.Camera.FOLLOW_LOCKON:
- this.deadzone = null;
- break;
- default:
- this.deadzone = null;
- break;
- }
- },
- /**
- * Move the camera focus on a display object instantly.
- * @method Phaser.Camera#focusOn
- * @param {any} displayObject - The display object to focus the camera on. Must have visible x/y properties.
- */
- focusOn: function (displayObject) {
- this.setPosition(Math.round(displayObject.x - this.view.halfWidth), Math.round(displayObject.y - this.view.halfHeight));
- },
- /**
- * Move the camera focus on a location instantly.
- * @method Phaser.Camera#focusOnXY
- * @param {number} x - X position.
- * @param {number} y - Y position.
- */
- focusOnXY: function (x, y) {
- this.setPosition(Math.round(x - this.view.halfWidth), Math.round(y - this.view.halfHeight));
- },
- /**
- * Update focusing and scrolling.
- * @method Phaser.Camera#update
- */
- update: function () {
- if (this.target)
- {
- this.updateTarget();
- }
- if (this.bounds)
- {
- this.checkBounds();
- }
- this.displayObject.position.x = -this.view.x;
- this.displayObject.position.y = -this.view.y;
- },
- /**
- * Internal method
- * @method Phaser.Camera#updateTarget
- * @private
- */
- updateTarget: function () {
- if (this.deadzone)
- {
- this._edge = this.target.x - this.deadzone.x;
- if (this.view.x > this._edge)
- {
- this.view.x = this._edge;
- }
- this._edge = this.target.x + this.target.width - this.deadzone.x - this.deadzone.width;
- if (this.view.x < this._edge)
- {
- this.view.x = this._edge;
- }
- this._edge = this.target.y - this.deadzone.y;
- if (this.view.y > this._edge)
- {
- this.view.y = this._edge;
- }
- this._edge = this.target.y + this.target.height - this.deadzone.y - this.deadzone.height;
- if (this.view.y < this._edge)
- {
- this.view.y = this._edge;
- }
- }
- else
- {
- this.focusOnXY(this.target.x, this.target.y);
- }
- },
- /**
- * Update the Camera bounds to match the game world.
- * @method Phaser.Camera#setBoundsToWorld
- */
- setBoundsToWorld: function () {
- this.bounds.setTo(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height);
- },
- /**
- * Method called to ensure the camera doesn't venture outside of the game world.
- * @method Phaser.Camera#checkWorldBounds
- */
- checkBounds: function () {
- this.atLimit.x = false;
- this.atLimit.y = false;
- // Make sure we didn't go outside the cameras bounds
- if (this.view.x <= this.bounds.x)
- {
- this.atLimit.x = true;
- this.view.x = this.bounds.x;
- }
- if (this.view.right >= this.bounds.right)
- {
- this.atLimit.x = true;
- this.view.x = this.bounds.right - this.width;
- }
- if (this.view.y <= this.bounds.top)
- {
- this.atLimit.y = true;
- this.view.y = this.bounds.top;
- }
- if (this.view.bottom >= this.bounds.bottom)
- {
- this.atLimit.y = true;
- this.view.y = this.bounds.bottom - this.height;
- }
- this.view.floor();
- },
- /**
- * A helper function to set both the X and Y properties of the camera at once
- * without having to use game.camera.x and game.camera.y.
- *
- * @method Phaser.Camera#setPosition
- * @param {number} x - X position.
- * @param {number} y - Y position.
- */
- setPosition: function (x, y) {
- this.view.x = x;
- this.view.y = y;
- if (this.bounds)
- {
- this.checkBounds();
- }
- },
- /**
- * Sets the size of the view rectangle given the width and height in parameters.
- *
- * @method Phaser.Camera#setSize
- * @param {number} width - The desired width.
- * @param {number} height - The desired height.
- */
- setSize: function (width, height) {
- this.view.width = width;
- this.view.height = height;
- },
- /**
- * Resets the camera back to 0,0 and un-follows any object it may have been tracking.
- *
- * @method Phaser.Camera#reset
- */
- reset: function () {
- this.target = null;
- this.view.x = 0;
- this.view.y = 0;
- }
- };
- Phaser.Camera.prototype.constructor = Phaser.Camera;
- /**
- * The Cameras x coordinate. This value is automatically clamped if it falls outside of the World bounds.
- * @name Phaser.Camera#x
- * @property {number} x - Gets or sets the cameras x position.
- */
- Object.defineProperty(Phaser.Camera.prototype, "x", {
- get: function () {
- return this.view.x;
- },
- set: function (value) {
- this.view.x = value;
- if (this.bounds)
- {
- this.checkBounds();
- }
- }
- });
- /**
- * The Cameras y coordinate. This value is automatically clamped if it falls outside of the World bounds.
- * @name Phaser.Camera#y
- * @property {number} y - Gets or sets the cameras y position.
- */
- Object.defineProperty(Phaser.Camera.prototype, "y", {
- get: function () {
- return this.view.y;
- },
- set: function (value) {
- this.view.y = value;
- if (this.bounds)
- {
- this.checkBounds();
- }
- }
- });
- /**
- * The Cameras width. By default this is the same as the Game size and should not be adjusted for now.
- * @name Phaser.Camera#width
- * @property {number} width - Gets or sets the cameras width.
- */
- Object.defineProperty(Phaser.Camera.prototype, "width", {
- get: function () {
- return this.view.width;
- },
- set: function (value) {
- this.view.width = value;
- }
- });
- /**
- * The Cameras height. By default this is the same as the Game size and should not be adjusted for now.
- * @name Phaser.Camera#height
- * @property {number} height - Gets or sets the cameras height.
- */
- Object.defineProperty(Phaser.Camera.prototype, "height", {
- get: function () {
- return this.view.height;
- },
- set: function (value) {
- this.view.height = value;
- }
- });
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * This is a base State class which can be extended if you are creating your own game.
- * It provides quick access to common functions such as the camera, cache, input, match, sound and more.
- *
- * @class Phaser.State
- * @constructor
- */
- Phaser.State = function () {
- /**
- * @property {Phaser.Game} game - A reference to the currently running Game.
- */
- this.game = null;
- /**
- * @property {Phaser.GameObjectFactory} add - Reference to the GameObjectFactory.
- */
- this.add = null;
- /**
- * @property {Phaser.GameObjectCreator} make - Reference to the GameObjectCreator.
- */
- this.make = null;
- /**
- * @property {Phaser.Camera} camera - A handy reference to world.camera.
- */
- this.camera = null;
- /**
- * @property {Phaser.Cache} cache - Reference to the assets cache.
- */
- this.cache = null;
- /**
- * @property {Phaser.Input} input - Reference to the input manager
- */
- this.input = null;
- /**
- * @property {Phaser.Loader} load - Reference to the assets loader.
- */
- this.load = null;
- /**
- * @property {Phaser.Math} math - Reference to the math helper.
- */
- this.math = null;
- /**
- * @property {Phaser.SoundManager} sound - Reference to the sound manager.
- */
- this.sound = null;
- /**
- * @property {Phaser.ScaleManager} scale - Reference to the game scale manager.
- */
- this.scale = null;
- /**
- * @property {Phaser.Stage} stage - Reference to the stage.
- */
- this.stage = null;
- /**
- * @property {Phaser.Time} time - Reference to the core game clock.
- */
- this.time = null;
- /**
- * @property {Phaser.TweenManager} tweens - Reference to the tween manager.
- */
- this.tweens = null;
- /**
- * @property {Phaser.World} world - Reference to the world.
- */
- this.world = null;
- /**
- * @property {Phaser.Particles} particles - The Particle Manager for the game. It is called during the game update loop and in turn updates any Emitters attached to it.
- */
- this.particles = null;
- /**
- * @property {Phaser.Physics} physics - Reference to the physics manager.
- */
- this.physics = null;
- /**
- * @property {Phaser.RandomDataGenerator} rnd - Reference to the random data generator.
- */
- this.rnd = null;
- };
- Phaser.State.prototype = {
- /**
- * Override this method to add some load operations.
- * If you need to use the loader, you may need to use them here.
- *
- * @method Phaser.State#preload
- */
- preload: function () {
- },
- /**
- * Put update logic here.
- *
- * @method Phaser.State#loadUpdate
- */
- loadUpdate: function () {
- },
- /**
- * Put render operations here.
- *
- * @method Phaser.State#loadRender
- */
- loadRender: function () {
- },
- /**
- * This method is called after the game engine successfully switches states.
- * Feel free to add any setup code here (do not load anything here, override preload() instead).
- *
- * @method Phaser.State#create
- */
- create: function () {
- },
- /**
- * Put update logic here.
- *
- * @method Phaser.State#update
- */
- update: function () {
- },
- /**
- * Put render operations here.
- *
- * @method Phaser.State#render
- */
- render: function () {
- },
- /**
- * This method will be called when game paused.
- *
- * @method Phaser.State#paused
- */
- paused: function () {
- },
- /**
- * This method will be called when the state is shut down (i.e. you switch to another state from this one).
- * @method Phaser.State#shutdown
- */
- shutdown: function () {
- }
- };
- Phaser.State.prototype.constructor = Phaser.State;
- /* jshint newcap: false */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * The State Manager is responsible for loading, setting up and switching game states.
- *
- * @class Phaser.StateManager
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- * @param {Phaser.State|Object} [pendingState=null] - A State object to seed the manager with.
- */
- Phaser.StateManager = function (game, pendingState) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running game.
- */
- this.game = game;
- /**
- * @property {Object} states - The object containing Phaser.States.
- */
- this.states = {};
- /**
- * @property {Phaser.State} _pendingState - The state to be switched to in the next frame.
- * @private
- */
- this._pendingState = null;
- if (typeof pendingState !== 'undefined' && pendingState !== null)
- {
- this._pendingState = pendingState;
- }
- /**
- * @property {boolean} _clearWorld - Clear the world when we switch state?
- * @private
- */
- this._clearWorld = false;
- /**
- * @property {boolean} _clearCache - Clear the cache when we switch state?
- * @private
- */
- this._clearCache = false;
- /**
- * @property {boolean} _created - Flag that sets if the State has been created or not.
- * @private
- */
- this._created = false;
- /**
- * @property {array} _args - Temporary container when you pass vars from one State to another.
- * @private
- */
- this._args = [];
- /**
- * @property {string} current - The current active State object (defaults to null).
- */
- this.current = '';
- /**
- * @property {function} onInitCallback - This will be called when the state is started (i.e. set as the current active state).
- */
- this.onInitCallback = null;
- /**
- * @property {function} onPreloadCallback - This will be called when init states (loading assets...).
- */
- this.onPreloadCallback = null;
- /**
- * @property {function} onCreateCallback - This will be called when create states (setup states...).
- */
- this.onCreateCallback = null;
- /**
- * @property {function} onUpdateCallback - This will be called when State is updated, this doesn't happen during load (@see onLoadUpdateCallback).
- */
- this.onUpdateCallback = null;
- /**
- * @property {function} onRenderCallback - This will be called when the State is rendered, this doesn't happen during load (see onLoadRenderCallback).
- */
- this.onRenderCallback = null;
- /**
- * @property {function} onPreRenderCallback - This will be called before the State is rendered and before the stage is cleared.
- */
- this.onPreRenderCallback = null;
- /**
- * @property {function} onLoadUpdateCallback - This will be called when the State is updated but only during the load process.
- */
- this.onLoadUpdateCallback = null;
- /**
- * @property {function} onLoadRenderCallback - This will be called when the State is rendered but only during the load process.
- */
- this.onLoadRenderCallback = null;
- /**
- * @property {function} onPausedCallback - This will be called when the state is paused.
- */
- this.onPausedCallback = null;
- /**
- * @property {function} onResumedCallback - This will be called when the state is resumed from a paused state.
- */
- this.onResumedCallback = null;
- /**
- * @property {function} onShutDownCallback - This will be called when the state is shut down (i.e. swapped to another state).
- */
- this.onShutDownCallback = null;
- };
- Phaser.StateManager.prototype = {
- /**
- * The Boot handler is called by Phaser.Game when it first starts up.
- * @method Phaser.StateManager#boot
- * @private
- */
- boot: function () {
- this.game.onPause.add(this.pause, this);
- this.game.onResume.add(this.resume, this);
- this.game.load.onLoadComplete.add(this.loadComplete, this);
- if (this._pendingState !== null)
- {
- if (typeof this._pendingState === 'string')
- {
- // State was already added, so just start it
- this.start(this._pendingState, false, false);
- }
- else
- {
- this.add('default', this._pendingState, true);
- }
- }
- },
- /**
- * Adds a new State into the StateManager. You must give each State a unique key by which you'll identify it.
- * The State can be either a Phaser.State object (or an object that extends it), a plain JavaScript object or a function.
- * If a function is given a new state object will be created by calling it.
- *
- * @method Phaser.StateManager#add
- * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
- * @param {Phaser.State|object|function} state - The state you want to switch to.
- * @param {boolean} [autoStart=false] - If true the State will be started immediately after adding it.
- */
- add: function (key, state, autoStart) {
- if (typeof autoStart === "undefined") { autoStart = false; }
- var newState;
- if (state instanceof Phaser.State)
- {
- newState = state;
- }
- else if (typeof state === 'object')
- {
- newState = state;
- newState.game = this.game;
- }
- else if (typeof state === 'function')
- {
- newState = new state(this.game);
- }
- this.states[key] = newState;
- if (autoStart)
- {
- if (this.game.isBooted)
- {
- this.start(key);
- }
- else
- {
- this._pendingState = key;
- }
- }
- return newState;
- },
- /**
- * Delete the given state.
- * @method Phaser.StateManager#remove
- * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
- */
- remove: function (key) {
- if (this.current === key)
- {
- this.callbackContext = null;
- this.onInitCallback = null;
- this.onShutDownCallback = null;
- this.onPreloadCallback = null;
- this.onLoadRenderCallback = null;
- this.onLoadUpdateCallback = null;
- this.onCreateCallback = null;
- this.onUpdateCallback = null;
- this.onRenderCallback = null;
- this.onPausedCallback = null;
- this.onResumedCallback = null;
- this.onDestroyCallback = null;
- }
- delete this.states[key];
- },
- /**
- * Start the given State. If a State is already running then State.shutDown will be called (if it exists) before switching to the new State.
- *
- * @method Phaser.StateManager#start
- * @param {string} key - The key of the state you want to start.
- * @param {boolean} [clearWorld=true] - Clear everything in the world? This clears the World display list fully (but not the Stage, so if you've added your own objects to the Stage they will need managing directly)
- * @param {boolean} [clearCache=false] - Clear the Game.Cache? This purges out all loaded assets. The default is false and you must have clearWorld=true if you want to clearCache as well.
- * @param {...*} parameter - Additional parameters that will be passed to the State.init function (if it has one).
- */
- start: function (key, clearWorld, clearCache) {
- if (typeof clearWorld === "undefined") { clearWorld = true; }
- if (typeof clearCache === "undefined") { clearCache = false; }
- if (this.checkState(key))
- {
- // Place the state in the queue. It will be started the next time the game loop starts.
- this._pendingState = key;
- this._clearWorld = clearWorld;
- this._clearCache = clearCache;
- if (arguments.length > 3)
- {
- this._args = Array.prototype.splice.call(arguments, 3);
- }
- }
- },
- /**
- * Restarts the current State. State.shutDown will be called (if it exists) before the State is restarted.
- *
- * @method Phaser.StateManager#restart
- * @param {boolean} [clearWorld=true] - Clear everything in the world? This clears the World display list fully (but not the Stage, so if you've added your own objects to the Stage they will need managing directly)
- * @param {boolean} [clearCache=false] - Clear the Game.Cache? This purges out all loaded assets. The default is false and you must have clearWorld=true if you want to clearCache as well.
- * @param {...*} parameter - Additional parameters that will be passed to the State.init function if it has one.
- */
- restart: function (clearWorld, clearCache) {
- if (typeof clearWorld === "undefined") { clearWorld = true; }
- if (typeof clearCache === "undefined") { clearCache = false; }
- // Place the state in the queue. It will be started the next time the game loop starts.
- this._pendingState = this.current;
- this._clearWorld = clearWorld;
- this._clearCache = clearCache;
- if (arguments.length > 3)
- {
- this._args = Array.prototype.splice.call(arguments, 3);
- }
- },
- /**
- * Used by onInit and onShutdown when those functions don't exist on the state
- * @method Phaser.StateManager#dummy
- * @private
- */
- dummy: function () {
- },
- /**
- * preUpdate is called right at the start of the game loop. It is responsible for changing to a new state that was requested previously.
- *
- * @method Phaser.StateManager#preUpdate
- */
- preUpdate: function () {
- if (this._pendingState && this.game.isBooted)
- {
- // Already got a state running?
- if (this.current)
- {
- this.onShutDownCallback.call(this.callbackContext, this.game);
- this.game.tweens.removeAll();
- this.game.camera.reset();
- this.game.input.reset(true);
- this.game.physics.clear();
- this.game.time.removeAll();
- if (this._clearWorld)
- {
- this.game.world.shutdown();
- if (this._clearCache === true)
- {
- this.game.cache.destroy();
- }
- }
- }
- this.setCurrentState(this._pendingState);
- if (this.onPreloadCallback)
- {
- this.game.load.reset();
- this.onPreloadCallback.call(this.callbackContext, this.game);
- // Is the loader empty?
- if (this.game.load.totalQueuedFiles() === 0)
- {
- this.loadComplete();
- }
- else
- {
- // Start the loader going as we have something in the queue
- this.game.load.start();
- }
- }
- else
- {
- // No init? Then there was nothing to load either
- this.loadComplete();
- }
- if (this.current === this._pendingState)
- {
- this._pendingState = null;
- }
- }
- },
- /**
- * Checks if a given phaser state is valid. A State is considered valid if it has at least one of the core functions: preload, create, update or render.
- *
- * @method Phaser.StateManager#checkState
- * @param {string} key - The key of the state you want to check.
- * @return {boolean} true if the State has the required functions, otherwise false.
- */
- checkState: function (key) {
- if (this.states[key])
- {
- var valid = false;
- if (this.states[key]['preload']) { valid = true; }
- if (this.states[key]['create']) { valid = true; }
- if (this.states[key]['update']) { valid = true; }
- if (this.states[key]['render']) { valid = true; }
- if (valid === false)
- {
- console.warn("Invalid Phaser State object given. Must contain at least a one of the required functions: preload, create, update or render");
- return false;
- }
- return true;
- }
- else
- {
- console.warn("Phaser.StateManager - No state found with the key: " + key);
- return false;
- }
- },
- /**
- * Links game properties to the State given by the key.
- * @method Phaser.StateManager#link
- * @param {string} key - State key.
- * @protected
- */
- link: function (key) {
- this.states[key].game = this.game;
- this.states[key].add = this.game.add;
- this.states[key].make = this.game.make;
- this.states[key].camera = this.game.camera;
- this.states[key].cache = this.game.cache;
- this.states[key].input = this.game.input;
- this.states[key].load = this.game.load;
- this.states[key].math = this.game.math;
- this.states[key].sound = this.game.sound;
- this.states[key].scale = this.game.scale;
- this.states[key].state = this;
- this.states[key].stage = this.game.stage;
- this.states[key].time = this.game.time;
- this.states[key].tweens = this.game.tweens;
- this.states[key].world = this.game.world;
- this.states[key].particles = this.game.particles;
- this.states[key].rnd = this.game.rnd;
- this.states[key].physics = this.game.physics;
- },
- /**
- * Sets the current State. Should not be called directly (use StateManager.start)
- * @method Phaser.StateManager#setCurrentState
- * @param {string} key - State key.
- * @private
- */
- setCurrentState: function (key) {
- this.callbackContext = this.states[key];
- this.link(key);
- // Used when the state is set as being the current active state
- this.onInitCallback = this.states[key]['init'] || this.dummy;
- this.onPreloadCallback = this.states[key]['preload'] || null;
- this.onLoadRenderCallback = this.states[key]['loadRender'] || null;
- this.onLoadUpdateCallback = this.states[key]['loadUpdate'] || null;
- this.onCreateCallback = this.states[key]['create'] || null;
- this.onUpdateCallback = this.states[key]['update'] || null;
- this.onPreRenderCallback = this.states[key]['preRender'] || null;
- this.onRenderCallback = this.states[key]['render'] || null;
- this.onPausedCallback = this.states[key]['paused'] || null;
- this.onResumedCallback = this.states[key]['resumed'] || null;
- // Used when the state is no longer the current active state
- this.onShutDownCallback = this.states[key]['shutdown'] || this.dummy;
- this.current = key;
- this._created = false;
- this.onInitCallback.apply(this.callbackContext, this._args);
- this._args = [];
- },
- /**
- * Gets the current State.
- *
- * @method Phaser.StateManager#getCurrentState
- * @return Phaser.State
- * @public
- */
- getCurrentState: function() {
- return this.states[this.current];
- },
- /**
- * @method Phaser.StateManager#loadComplete
- * @protected
- */
- loadComplete: function () {
- if (this._created === false && this.onCreateCallback)
- {
- this._created = true;
- this.onCreateCallback.call(this.callbackContext, this.game);
- }
- else
- {
- this._created = true;
- }
- },
- /**
- * @method Phaser.StateManager#pause
- * @protected
- */
- pause: function () {
- if (this._created && this.onPausedCallback)
- {
- this.onPausedCallback.call(this.callbackContext, this.game);
- }
- },
- /**
- * @method Phaser.StateManager#resume
- * @protected
- */
- resume: function () {
- if (this._created && this.onResumedCallback)
- {
- this.onResumedCallback.call(this.callbackContext, this.game);
- }
- },
- /**
- * @method Phaser.StateManager#update
- * @protected
- */
- update: function () {
- if (this._created && this.onUpdateCallback)
- {
- this.onUpdateCallback.call(this.callbackContext, this.game);
- }
- else
- {
- if (this.onLoadUpdateCallback)
- {
- this.onLoadUpdateCallback.call(this.callbackContext, this.game);
- }
- }
- },
- /**
- * @method Phaser.StateManager#preRender
- * @protected
- */
- preRender: function () {
- if (this.onPreRenderCallback)
- {
- this.onPreRenderCallback.call(this.callbackContext, this.game);
- }
- },
- /**
- * @method Phaser.StateManager#render
- * @protected
- */
- render: function () {
- if (this._created && this.onRenderCallback)
- {
- if (this.game.renderType === Phaser.CANVAS)
- {
- this.game.context.save();
- this.game.context.setTransform(1, 0, 0, 1, 0, 0);
- }
- this.onRenderCallback.call(this.callbackContext, this.game);
- if (this.game.renderType === Phaser.CANVAS)
- {
- this.game.context.restore();
- }
- }
- else
- {
- if (this.onLoadRenderCallback)
- {
- this.onLoadRenderCallback.call(this.callbackContext, this.game);
- }
- }
- },
- /**
- * Removes all StateManager callback references to the State object, nulls the game reference and clears the States object.
- * You don't recover from this without rebuilding the Phaser instance again.
- * @method Phaser.StateManager#destroy
- */
- destroy: function () {
- this.callbackContext = null;
- this.onInitCallback = null;
- this.onShutDownCallback = null;
- this.onPreloadCallback = null;
- this.onLoadRenderCallback = null;
- this.onLoadUpdateCallback = null;
- this.onCreateCallback = null;
- this.onUpdateCallback = null;
- this.onRenderCallback = null;
- this.onPausedCallback = null;
- this.onResumedCallback = null;
- this.onDestroyCallback = null;
- this.game = null;
- this.states = {};
- this._pendingState = null;
- }
- };
- Phaser.StateManager.prototype.constructor = Phaser.StateManager;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * A basic linked list data structure.
- *
- * @class Phaser.LinkedList
- * @constructor
- */
- Phaser.LinkedList = function () {
- /**
- * @property {object} next - Next element in the list.
- * @default
- */
- this.next = null;
- /**
- * @property {object} prev - Previous element in the list.
- * @default
- */
- this.prev = null;
- /**
- * @property {object} first - First element in the list.
- * @default
- */
- this.first = null;
- /**
- * @property {object} last - Last element in the list.
- * @default
- */
- this.last = null;
- /**
- * @property {object} game - Number of elements in the list.
- * @default
- */
- this.total = 0;
- };
- Phaser.LinkedList.prototype = {
- /**
- * Adds a new element to this linked list.
- *
- * @method Phaser.LinkedList#add
- * @param {object} child - The element to add to this list. Can be a Phaser.Sprite or any other object you need to quickly iterate through.
- * @return {object} The child that was added.
- */
- add: function (child) {
- // If the list is empty
- if (this.total === 0 && this.first == null && this.last == null)
- {
- this.first = child;
- this.last = child;
- this.next = child;
- child.prev = this;
- this.total++;
- return child;
- }
- // Get gets appended to the end of the list, regardless of anything, and it won't have any children of its own (non-nested list)
- this.last.next = child;
- child.prev = this.last;
- this.last = child;
- this.total++;
- return child;
- },
- /**
- * Removes the given element from this linked list if it exists.
- *
- * @method Phaser.LinkedList#remove
- * @param {object} child - The child to be removed from the list.
- */
- remove: function (child) {
- if (child == this.first)
- {
- // It was 'first', make 'first' point to first.next
- this.first = this.first.next;
- }
- else if (child == this.last)
- {
- // It was 'last', make 'last' point to last.prev
- this.last = this.last.prev;
- }
- if (child.prev)
- {
- // make child.prev.next point to childs.next instead of child
- child.prev.next = child.next;
- }
- if (child.next)
- {
- // make child.next.prev point to child.prev instead of child
- child.next.prev = child.prev;
- }
- child.next = child.prev = null;
- if (this.first == null )
- {
- this.last = null;
- }
- this.total--;
- },
- /**
- * Calls a function on all members of this list, using the member as the context for the callback.
- * The function must exist on the member.
- *
- * @method Phaser.LinkedList#callAll
- * @param {function} callback - The function to call.
- */
- callAll: function (callback) {
- if (!this.first || !this.last)
- {
- return;
- }
- var entity = this.first;
- do
- {
- if (entity && entity[callback])
- {
- entity[callback].call(entity);
- }
- entity = entity.next;
- }
- while(entity != this.last.next);
- }
- };
- Phaser.LinkedList.prototype.constructor = Phaser.LinkedList;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * @class Phaser.Signal
- * @classdesc A Signal is used for object communication via a custom broadcaster instead of Events.
- * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
- * @constructor
- */
- Phaser.Signal = function () {
- /**
- * @property {Array.<Phaser.SignalBinding>} _bindings - Internal variable.
- * @private
- */
- this._bindings = [];
- /**
- * @property {any} _prevParams - Internal variable.
- * @private
- */
- this._prevParams = null;
- // enforce dispatch to aways work on same context (#47)
- var self = this;
- /**
- * @property {function} dispatch - The dispatch function is what sends the Signal out.
- */
- this.dispatch = function(){
- Phaser.Signal.prototype.dispatch.apply(self, arguments);
- };
- };
- Phaser.Signal.prototype = {
- /**
- * If Signal should keep record of previously dispatched parameters and
- * automatically execute listener during `add()`/`addOnce()` if Signal was
- * already dispatched before.
- * @property {boolean} memorize
- */
- memorize: false,
- /**
- * @property {boolean} _shouldPropagate
- * @private
- */
- _shouldPropagate: true,
- /**
- * If Signal is active and should broadcast events.
- * <p><strong>IMPORTANT:</strong> Setting this property during a dispatch will only affect the next dispatch, if you want to stop the propagation of a signal use `halt()` instead.</p>
- * @property {boolean} active
- * @default
- */
- active: true,
- /**
- * @method Phaser.Signal#validateListener
- * @param {function} listener - Signal handler function.
- * @param {string} fnName - Function name.
- * @private
- */
- validateListener: function (listener, fnName) {
- if (typeof listener !== 'function') {
- throw new Error('listener is a required param of {fn}() and should be a Function.'.replace('{fn}', fnName));
- }
- },
- /**
- * @method Phaser.Signal#_registerListener
- * @param {function} listener - Signal handler function.
- * @param {boolean} isOnce - Description.
- * @param {object} [listenerContext] - Description.
- * @param {number} [priority] - The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0).
- * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
- * @private
- */
- _registerListener: function (listener, isOnce, listenerContext, priority) {
- var prevIndex = this._indexOfListener(listener, listenerContext),
- binding;
- if (prevIndex !== -1) {
- binding = this._bindings[prevIndex];
- if (binding.isOnce() !== isOnce) {
- throw new Error('You cannot add' + (isOnce ? '' : 'Once') + '() then add' + (!isOnce ? '' : 'Once') + '() the same listener without removing the relationship first.');
- }
- } else {
- binding = new Phaser.SignalBinding(this, listener, isOnce, listenerContext, priority);
- this._addBinding(binding);
- }
- if (this.memorize && this._prevParams) {
- binding.execute(this._prevParams);
- }
- return binding;
- },
- /**
- * @method Phaser.Signal#_addBinding
- * @param {Phaser.SignalBinding} binding - An Object representing the binding between the Signal and listener.
- * @private
- */
- _addBinding: function (binding) {
- //simplified insertion sort
- var n = this._bindings.length;
- do { --n; } while (this._bindings[n] && binding._priority <= this._bindings[n]._priority);
- this._bindings.splice(n + 1, 0, binding);
- },
- /**
- * @method Phaser.Signal#_indexOfListener
- * @param {function} listener - Signal handler function.
- * @return {number} Description.
- * @private
- */
- _indexOfListener: function (listener, context) {
- var n = this._bindings.length,
- cur;
- while (n--) {
- cur = this._bindings[n];
- if (cur._listener === listener && cur.context === context) {
- return n;
- }
- }
- return -1;
- },
- /**
- * Check if listener was attached to Signal.
- *
- * @method Phaser.Signal#has
- * @param {Function} listener - Signal handler function.
- * @param {Object} [context] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
- * @return {boolean} If Signal has the specified listener.
- */
- has: function (listener, context) {
- return this._indexOfListener(listener, context) !== -1;
- },
- /**
- * Add a listener to the signal.
- *
- * @method Phaser.Signal#add
- * @param {function} listener - Signal handler function.
- * @param {object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function).
- * @param {number} [priority] The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0).
- * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
- */
- add: function (listener, listenerContext, priority) {
- this.validateListener(listener, 'add');
- return this._registerListener(listener, false, listenerContext, priority);
- },
- /**
- * Add listener to the signal that should be removed after first execution (will be executed only once).
- *
- * @method Phaser.Signal#addOnce
- * @param {function} listener Signal handler function.
- * @param {object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function).
- * @param {number} [priority] The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0)
- * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
- */
- addOnce: function (listener, listenerContext, priority) {
- this.validateListener(listener, 'addOnce');
- return this._registerListener(listener, true, listenerContext, priority);
- },
- /**
- * Remove a single listener from the dispatch queue.
- *
- * @method Phaser.Signal#remove
- * @param {function} listener Handler function that should be removed.
- * @param {object} [context] Execution context (since you can add the same handler multiple times if executing in a different context).
- * @return {function} Listener handler function.
- */
- remove: function (listener, context) {
- this.validateListener(listener, 'remove');
- var i = this._indexOfListener(listener, context);
- if (i !== -1)
- {
- this._bindings[i]._destroy(); //no reason to a Phaser.SignalBinding exist if it isn't attached to a signal
- this._bindings.splice(i, 1);
- }
- return listener;
- },
- /**
- * Remove all listeners from the Signal.
- *
- * @method Phaser.Signal#removeAll
- */
- removeAll: function () {
- var n = this._bindings.length;
- while (n--) {
- this._bindings[n]._destroy();
- }
- this._bindings.length = 0;
- },
- /**
- * Gets the total number of listeneres attached to ths Signal.
- *
- * @method Phaser.Signal#getNumListeners
- * @return {number} Number of listeners attached to the Signal.
- */
- getNumListeners: function () {
- return this._bindings.length;
- },
- /**
- * Stop propagation of the event, blocking the dispatch to next listeners on the queue.
- * IMPORTANT: should be called only during signal dispatch, calling it before/after dispatch won't affect signal broadcast.
- * @see Signal.prototype.disable
- *
- * @method Phaser.Signal#halt
- */
- halt: function () {
- this._shouldPropagate = false;
- },
- /**
- * Dispatch/Broadcast Signal to all listeners added to the queue.
- *
- * @method Phaser.Signal#dispatch
- * @param {any} [params] - Parameters that should be passed to each handler.
- */
- dispatch: function () {
- if (!this.active)
- {
- return;
- }
- var paramsArr = Array.prototype.slice.call(arguments);
- var n = this._bindings.length;
- var bindings;
- if (this.memorize)
- {
- this._prevParams = paramsArr;
- }
- if (!n)
- {
- // Should come after memorize
- return;
- }
- bindings = this._bindings.slice(); //clone array in case add/remove items during dispatch
- this._shouldPropagate = true; //in case `halt` was called before dispatch or during the previous dispatch.
- //execute all callbacks until end of the list or until a callback returns `false` or stops propagation
- //reverse loop since listeners with higher priority will be added at the end of the list
- do { n--; } while (bindings[n] && this._shouldPropagate && bindings[n].execute(paramsArr) !== false);
- },
- /**
- * Forget memorized arguments.
- * @see Signal.memorize
- *
- * @method Phaser.Signal#forget
- */
- forget: function(){
- this._prevParams = null;
- },
- /**
- * Remove all bindings from signal and destroy any reference to external objects (destroy Signal object).
- * IMPORTANT: calling any method on the signal instance after calling dispose will throw errors.
- *
- * @method Phaser.Signal#dispose
- */
- dispose: function () {
- this.removeAll();
- delete this._bindings;
- delete this._prevParams;
- },
- /**
- *
- * @method Phaser.Signal#toString
- * @return {string} String representation of the object.
- */
- toString: function () {
- return '[Phaser.Signal active:'+ this.active +' numListeners:'+ this.getNumListeners() +']';
- }
- };
- Phaser.Signal.prototype.constructor = Phaser.Signal;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * @class Phaser.SignalBinding
- * @classdesc Object that represents a binding between a Signal and a listener function.
- * This is an internal constructor and shouldn't be called by regular users.
- * Inspired by Joa Ebert AS3 SignalBinding and Robert Penner's Slot classes.
- *
- * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
- * @constructor
- * @param {Phaser.Signal} signal - Reference to Signal object that listener is currently bound to.
- * @param {function} listener - Handler function bound to the signal.
- * @param {boolean} isOnce - If binding should be executed just once.
- * @param {object} [listenerContext] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
- * @param {number} [priority] - The priority level of the event listener. (default = 0).
- */
- Phaser.SignalBinding = function (signal, listener, isOnce, listenerContext, priority) {
- /**
- * @property {Phaser.Game} _listener - Handler function bound to the signal.
- * @private
- */
- this._listener = listener;
- /**
- * @property {boolean} _isOnce - If binding should be executed just once.
- * @private
- */
- this._isOnce = isOnce;
- /**
- * @property {object|undefined|null} context - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
- */
- this.context = listenerContext;
- /**
- * @property {Phaser.Signal} _signal - Reference to Signal object that listener is currently bound to.
- * @private
- */
- this._signal = signal;
- /**
- * @property {number} _priority - Listener priority.
- * @private
- */
- this._priority = priority || 0;
- };
- Phaser.SignalBinding.prototype = {
- /**
- * If binding is active and should be executed.
- * @property {boolean} active
- * @default
- */
- active: true,
- /**
- * Default parameters passed to listener during `Signal.dispatch` and `SignalBinding.execute` (curried parameters).
- * @property {array|null} params
- * @default
- */
- params: null,
- /**
- * Call listener passing arbitrary parameters.
- * If binding was added using `Signal.addOnce()` it will be automatically removed from signal dispatch queue, this method is used internally for the signal dispatch.
- * @method Phaser.SignalBinding#execute
- * @param {array} [paramsArr] - Array of parameters that should be passed to the listener.
- * @return {any} Value returned by the listener.
- */
- execute: function(paramsArr) {
- var handlerReturn, params;
- if (this.active && !!this._listener)
- {
- params = this.params ? this.params.concat(paramsArr) : paramsArr;
- handlerReturn = this._listener.apply(this.context, params);
- if (this._isOnce)
- {
- this.detach();
- }
- }
- return handlerReturn;
- },
- /**
- * Detach binding from signal.
- * alias to: @see mySignal.remove(myBinding.getListener());
- * @method Phaser.SignalBinding#detach
- * @return {function|null} Handler function bound to the signal or `null` if binding was previously detached.
- */
- detach: function () {
- return this.isBound() ? this._signal.remove(this._listener, this.context) : null;
- },
- /**
- * @method Phaser.SignalBinding#isBound
- * @return {boolean} True if binding is still bound to the signal and has a listener.
- */
- isBound: function () {
- return (!!this._signal && !!this._listener);
- },
- /**
- * @method Phaser.SignalBinding#isOnce
- * @return {boolean} If SignalBinding will only be executed once.
- */
- isOnce: function () {
- return this._isOnce;
- },
- /**
- * @method Phaser.SignalBinding#getListener
- * @return {Function} Handler function bound to the signal.
- */
- getListener: function () {
- return this._listener;
- },
- /**
- * @method Phaser.SignalBinding#getSignal
- * @return {Signal} Signal that listener is currently bound to.
- */
- getSignal: function () {
- return this._signal;
- },
- /**
- * @method Phaser.SignalBinding#_destroy
- * Delete instance properties
- * @private
- */
- _destroy: function () {
- delete this._signal;
- delete this._listener;
- delete this.context;
- },
- /**
- * @method Phaser.SignalBinding#toString
- * @return {string} String representation of the object.
- */
- toString: function () {
- return '[Phaser.SignalBinding isOnce:' + this._isOnce +', isBound:'+ this.isBound() +', active:' + this.active + ']';
- }
- };
- Phaser.SignalBinding.prototype.constructor = Phaser.SignalBinding;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * This is a base Filter template to use for any Phaser filter development.
- *
- * @class Phaser.Filter
- * @classdesc Phaser - Filter
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- * @param {Object} uniforms - Uniform mappings object
- * @param {Array} fragmentSrc - The fragment shader code.
- */
- Phaser.Filter = function (game, uniforms, fragmentSrc) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running game.
- */
- this.game = game;
- /**
- * @property {number} type - The const type of this object, either Phaser.WEBGL_FILTER or Phaser.CANVAS_FILTER.
- * @default
- */
- this.type = Phaser.WEBGL_FILTER;
- /**
- * An array of passes - some filters contain a few steps this array simply stores the steps in a linear fashion.
- * For example the blur filter has two passes blurX and blurY.
- * @property {array} passes - An array of filter objects.
- * @private
- */
- this.passes = [this];
- /**
- * @property {array} shaders - Array an array of shaders.
- * @private
- */
- this.shaders = [];
- /**
- * @property {boolean} dirty - Internal PIXI var.
- * @default
- */
- this.dirty = true;
- /**
- * @property {number} padding - Internal PIXI var.
- * @default
- */
- this.padding = 0;
- /**
- * @property {object} uniforms - Default uniform mappings.
- */
- this.uniforms = {
- time: { type: '1f', value: 0 },
- resolution: { type: '2f', value: { x: 256, y: 256 }},
- mouse: { type: '2f', value: { x: 0.0, y: 0.0 }}
- };
- /**
- * @property {array} fragmentSrc - The fragment shader code.
- */
- this.fragmentSrc = fragmentSrc || [];
- };
- Phaser.Filter.prototype = {
- /**
- * Should be over-ridden.
- * @method Phaser.Filter#init
- */
- init: function () {
- // This should be over-ridden. Will receive a variable number of arguments.
- },
- /**
- * Set the resolution uniforms on the filter.
- * @method Phaser.Filter#setResolution
- * @param {number} width - The width of the display.
- * @param {number} height - The height of the display.
- */
- setResolution: function (width, height) {
- this.uniforms.resolution.value.x = width;
- this.uniforms.resolution.value.y = height;
- },
- /**
- * Updates the filter.
- * @method Phaser.Filter#update
- * @param {Phaser.Pointer} [pointer] - A Pointer object to use for the filter. The coordinates are mapped to the mouse uniform.
- */
- update: function (pointer) {
- if (typeof pointer !== 'undefined')
- {
- if (pointer.x > 0)
- {
- this.uniforms.mouse.x = pointer.x.toFixed(2);
- }
- if (pointer.y > 0)
- {
- this.uniforms.mouse.y = pointer.y.toFixed(2);
- }
- }
- this.uniforms.time.value = this.game.time.totalElapsedSeconds();
- },
- /**
- * Clear down this Filter and null out references
- * @method Phaser.Filter#destroy
- */
- destroy: function () {
- this.game = null;
- }
- };
- Phaser.Filter.prototype.constructor = Phaser.Filter;
- /**
- * @name Phaser.Filter#width
- * @property {number} width - The width (resolution uniform)
- */
- Object.defineProperty(Phaser.Filter.prototype, 'width', {
- get: function() {
- return this.uniforms.resolution.value.x;
- },
- set: function(value) {
- this.uniforms.resolution.value.x = value;
- }
- });
- /**
- * @name Phaser.Filter#height
- * @property {number} height - The height (resolution uniform)
- */
- Object.defineProperty(Phaser.Filter.prototype, 'height', {
- get: function() {
- return this.uniforms.resolution.value.y;
- },
- set: function(value) {
- this.uniforms.resolution.value.y = value;
- }
- });
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * This is a base Plugin template to use for any Phaser plugin development.
- *
- * @class Phaser.Plugin
- * @classdesc Phaser - Plugin
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- * @param {Any} parent - The object that owns this plugin, usually Phaser.PluginManager.
- */
- Phaser.Plugin = function (game, parent) {
- if (typeof parent === 'undefined') { parent = null; }
- /**
- * @property {Phaser.Game} game - A reference to the currently running game.
- */
- this.game = game;
- /**
- * @property {Any} parent - The parent of this plugin. If added to the PluginManager the parent will be set to that, otherwise it will be null.
- */
- this.parent = parent;
- /**
- * @property {boolean} active - A Plugin with active=true has its preUpdate and update methods called by the parent, otherwise they are skipped.
- * @default
- */
- this.active = false;
- /**
- * @property {boolean} visible - A Plugin with visible=true has its render and postRender methods called by the parent, otherwise they are skipped.
- * @default
- */
- this.visible = false;
- /**
- * @property {boolean} hasPreUpdate - A flag to indicate if this plugin has a preUpdate method.
- * @default
- */
- this.hasPreUpdate = false;
- /**
- * @property {boolean} hasUpdate - A flag to indicate if this plugin has an update method.
- * @default
- */
- this.hasUpdate = false;
- /**
- * @property {boolean} hasPostUpdate - A flag to indicate if this plugin has a postUpdate method.
- * @default
- */
- this.hasPostUpdate = false;
- /**
- * @property {boolean} hasRender - A flag to indicate if this plugin has a render method.
- * @default
- */
- this.hasRender = false;
- /**
- * @property {boolean} hasPostRender - A flag to indicate if this plugin has a postRender method.
- * @default
- */
- this.hasPostRender = false;
- };
- Phaser.Plugin.prototype = {
- /**
- * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
- * It is only called if active is set to true.
- * @method Phaser.Plugin#preUpdate
- */
- preUpdate: function () {
- },
- /**
- * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
- * It is only called if active is set to true.
- * @method Phaser.Plugin#update
- */
- update: function () {
- },
- /**
- * Render is called right after the Game Renderer completes, but before the State.render.
- * It is only called if visible is set to true.
- * @method Phaser.Plugin#render
- */
- render: function () {
- },
- /**
- * Post-render is called after the Game Renderer and State.render have run.
- * It is only called if visible is set to true.
- * @method Phaser.Plugin#postRender
- */
- postRender: function () {
- },
- /**
- * Clear down this Plugin and null out references
- * @method Phaser.Plugin#destroy
- */
- destroy: function () {
- this.game = null;
- this.parent = null;
- this.active = false;
- this.visible = false;
- }
- };
- Phaser.Plugin.prototype.constructor = Phaser.Plugin;
- /* jshint newcap: false */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * The Plugin Manager is responsible for the loading, running and unloading of Phaser Plugins.
- *
- * @class Phaser.PluginManager
- * @classdesc Phaser - PluginManager
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- */
- Phaser.PluginManager = function(game) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running game.
- */
- this.game = game;
- /**
- * @property {array} plugins - An array of all the plugins being managed by this PluginManager.
- */
- this.plugins = [];
- /**
- * @property {number} _len - Internal cache var.
- * @private
- */
- this._len = 0;
- /**
- * @property {number} _i - Internal cache var.
- * @private
- */
- this._i = 0;
- };
- Phaser.PluginManager.prototype = {
- /**
- * Add a new Plugin into the PluginManager.
- * The Plugin must have 2 properties: game and parent. Plugin.game is set to ths game reference the PluginManager uses, and parent is set to the PluginManager.
- *
- * @method Phaser.PluginManager#add
- * @param {object|Phaser.Plugin} plugin - The Plugin to add into the PluginManager. This can be a function or an existing object.
- * @return {Phaser.Plugin} The Plugin that was added to the manager.
- */
- add: function (plugin) {
- var result = false;
- // Prototype?
- if (typeof plugin === 'function')
- {
- plugin = new plugin(this.game, this._parent);
- }
- else
- {
- plugin.game = this.game;
- plugin.parent = this;
- }
- // Check for methods now to avoid having to do this every loop
- if (typeof plugin['preUpdate'] === 'function')
- {
- plugin.hasPreUpdate = true;
- result = true;
- }
- if (typeof plugin['update'] === 'function')
- {
- plugin.hasUpdate = true;
- result = true;
- }
- if (typeof plugin['postUpdate'] === 'function')
- {
- plugin.hasPostUpdate = true;
- result = true;
- }
- if (typeof plugin['render'] === 'function')
- {
- plugin.hasRender = true;
- result = true;
- }
- if (typeof plugin['postRender'] === 'function')
- {
- plugin.hasPostRender = true;
- result = true;
- }
- // The plugin must have at least one of the above functions to be added to the PluginManager.
- if (result)
- {
- if (plugin.hasPreUpdate || plugin.hasUpdate || plugin.hasPostUpdate)
- {
- plugin.active = true;
- }
- if (plugin.hasRender || plugin.hasPostRender)
- {
- plugin.visible = true;
- }
- this._len = this.plugins.push(plugin);
- // Allows plugins to run potentially destructive code outside of the constructor, and only if being added to the PluginManager
- if (typeof plugin['init'] === 'function')
- {
- plugin.init();
- }
- return plugin;
- }
- else
- {
- return null;
- }
- },
- /**
- * Remove a Plugin from the PluginManager. It calls Plugin.destroy on the plugin before removing it from the manager.
- *
- * @method Phaser.PluginManager#remove
- * @param {Phaser.Plugin} plugin - The plugin to be removed.
- */
- remove: function (plugin) {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i] === plugin)
- {
- plugin.destroy();
- this.plugins.splice(this._i, 1);
- this._len--;
- return;
- }
- }
- },
- /**
- * Remove all Plugins from the PluginManager. It calls Plugin.destroy on every plugin before removing it from the manager.
- *
- * @method Phaser.PluginManager#removeAll
- */
- removeAll: function() {
- this._i = this._len;
- while (this._i--)
- {
- this.plugins[this._i].destroy();
- }
- this.plugins.length = 0;
- this._len = 0;
- },
- /**
- * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
- * It only calls plugins who have active=true.
- *
- * @method Phaser.PluginManager#preUpdate
- */
- preUpdate: function () {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i].active && this.plugins[this._i].hasPreUpdate)
- {
- this.plugins[this._i].preUpdate();
- }
- }
- },
- /**
- * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
- * It only calls plugins who have active=true.
- *
- * @method Phaser.PluginManager#update
- */
- update: function () {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i].active && this.plugins[this._i].hasUpdate)
- {
- this.plugins[this._i].update();
- }
- }
- },
- /**
- * PostUpdate is the last thing to be called before the world render.
- * In particular, it is called after the world postUpdate, which means the camera has been adjusted.
- * It only calls plugins who have active=true.
- *
- * @method Phaser.PluginManager#postUpdate
- */
- postUpdate: function () {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i].active && this.plugins[this._i].hasPostUpdate)
- {
- this.plugins[this._i].postUpdate();
- }
- }
- },
- /**
- * Render is called right after the Game Renderer completes, but before the State.render.
- * It only calls plugins who have visible=true.
- *
- * @method Phaser.PluginManager#render
- */
- render: function () {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i].visible && this.plugins[this._i].hasRender)
- {
- this.plugins[this._i].render();
- }
- }
- },
- /**
- * Post-render is called after the Game Renderer and State.render have run.
- * It only calls plugins who have visible=true.
- *
- * @method Phaser.PluginManager#postRender
- */
- postRender: function () {
- this._i = this._len;
- while (this._i--)
- {
- if (this.plugins[this._i].visible && this.plugins[this._i].hasPostRender)
- {
- this.plugins[this._i].postRender();
- }
- }
- },
- /**
- * Clear down this PluginManager, calls destroy on every plugin and nulls out references.
- *
- * @method Phaser.PluginManager#destroy
- */
- destroy: function () {
- this.removeAll();
- this.game = null;
- }
- };
- Phaser.PluginManager.prototype.constructor = Phaser.PluginManager;
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * The Stage controls the canvas on which everything is displayed. It handles display within the browser,
- * focus handling, game resizing, scaling and the pause, boot and orientation screens.
- *
- * @class Phaser.Stage
- * @extends PIXI.Stage
- * @constructor
- * @param {Phaser.Game} game - Game reference to the currently running game.
- * @param {number} width - Width of the canvas element.
- * @param {number} height - Height of the canvas element.
- */
- Phaser.Stage = function (game, width, height) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running Game.
- */
- this.game = game;
- /**
- * @property {Phaser.Point} offset - Holds the offset coordinates of the Game.canvas from the top-left of the browser window (used by Input and other classes)
- */
- this.offset = new Phaser.Point();
- PIXI.Stage.call(this, 0x000000, false);
- /**
- * @property {string} name - The name of this object.
- * @default
- */
- this.name = '_stage_root';
- this.interactive = false;
- /**
- * @property {boolean} disableVisibilityChange - By default if the browser tab loses focus the game will pause. You can stop that behaviour by setting this property to true.
- * @default
- */
- this.disableVisibilityChange = false;
- /**
- * @property {number|false} checkOffsetInterval - The time (in ms) between which the stage should check to see if it has moved.
- * @default
- */
- this.checkOffsetInterval = 2500;
- /**
- * @property {boolean} exists - If exists is true the Stage and all children are updated, otherwise it is skipped.
- * @default
- */
- this.exists = true;
- /**
- * @property {number} currentRenderOrderID - Reset each frame, keeps a count of the total number of objects updated.
- */
- this.currentRenderOrderID = 0;
- /**
- * @property {string} hiddenVar - The page visibility API event name.
- * @private
- */
- this._hiddenVar = 'hidden';
- /**
- * @property {number} _nextOffsetCheck - The time to run the next offset check.
- * @private
- */
- this._nextOffsetCheck = 0;
- /**
- * @property {number} _backgroundColor - Stage background color.
- * @private
- */
- this._backgroundColor = 0x000000;
- if (game.config)
- {
- this.parseConfig(game.config);
- }
- else
- {
- this.game.canvas = Phaser.Canvas.create(width, height);
- this.game.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
- }
- };
- Phaser.Stage.prototype = Object.create(PIXI.Stage.prototype);
- Phaser.Stage.prototype.constructor = Phaser.Stage;
- /**
- * This is called automatically after the plugins preUpdate and before the State.update.
- * Most objects have preUpdate methods and it's where initial movement and positioning is done.
- *
- * @method Phaser.Stage#preUpdate
- */
- Phaser.Stage.prototype.preUpdate = function () {
- this.currentRenderOrderID = 0;
- // This can't loop in reverse, we need the orderID to be in sequence
- var len = this.children.length;
- for (var i = 0; i < len; i++)
- {
- this.children[i].preUpdate();
- }
- };
- /**
- * This is called automatically after the State.update, but before particles or plugins update.
- *
- * @method Phaser.Stage#update
- */
- Phaser.Stage.prototype.update = function () {
- var i = this.children.length;
- while (i--)
- {
- this.children[i].update();
- }
- };
- /**
- * This is called automatically before the renderer runs and after the plugins have updated.
- * In postUpdate this is where all the final physics calculatations and object positioning happens.
- * The objects are processed in the order of the display list.
- * The only exception to this is if the camera is following an object, in which case that is updated first.
- *
- * @method Phaser.Stage#postUpdate
- */
- Phaser.Stage.prototype.postUpdate = function () {
- if (this.game.world.camera.target)
- {
- this.game.world.camera.target.postUpdate();
- this.game.world.camera.update();
- var i = this.children.length;
- while (i--)
- {
- if (this.children[i] !== this.game.world.camera.target)
- {
- this.children[i].postUpdate();
- }
- }
- }
- else
- {
- this.game.world.camera.update();
- var i = this.children.length;
- while (i--)
- {
- this.children[i].postUpdate();
- }
- }
- if (this.checkOffsetInterval !== false)
- {
- if (this.game.time.now > this._nextOffsetCheck)
- {
- Phaser.Canvas.getOffset(this.game.canvas, this.offset);
- this._nextOffsetCheck = this.game.time.now + this.checkOffsetInterval;
- }
- }
- };
- /**
- * Parses a Game configuration object.
- *
- * @method Phaser.Stage#parseConfig
- * @protected
- */
- Phaser.Stage.prototype.parseConfig = function (config) {
- if (config['canvasID'])
- {
- this.game.canvas = Phaser.Canvas.create(this.game.width, this.game.height, config['canvasID']);
- }
- else
- {
- this.game.canvas = Phaser.Canvas.create(this.game.width, this.game.height);
- }
- if (config['canvasStyle'])
- {
- this.game.canvas.stlye = config['canvasStyle'];
- }
- else
- {
- this.game.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
- }
- if (config['checkOffsetInterval'])
- {
- this.checkOffsetInterval = config['checkOffsetInterval'];
- }
- if (config['disableVisibilityChange'])
- {
- this.disableVisibilityChange = config['disableVisibilityChange'];
- }
- if (config['fullScreenScaleMode'])
- {
- this.fullScreenScaleMode = config['fullScreenScaleMode'];
- }
- if (config['scaleMode'])
- {
- this.scaleMode = config['scaleMode'];
- }
- if (config['backgroundColor'])
- {
- this.backgroundColor = config['backgroundColor'];
- }
- };
- /**
- * Initialises the stage and adds the event listeners.
- * @method Phaser.Stage#boot
- * @private
- */
- Phaser.Stage.prototype.boot = function () {
- Phaser.Canvas.getOffset(this.game.canvas, this.offset);
- this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, this.game.width, this.game.height);
- var _this = this;
- this._onChange = function (event) {
- return _this.visibilityChange(event);
- };
- Phaser.Canvas.setUserSelect(this.game.canvas, 'none');
- Phaser.Canvas.setTouchAction(this.game.canvas, 'none');
- this.checkVisibility();
- };
- /**
- * Starts a page visibility event listener running, or window.blur/focus if not supported by the browser.
- * @method Phaser.Stage#checkVisibility
- */
- Phaser.Stage.prototype.checkVisibility = function () {
- if (document.webkitHidden !== undefined)
- {
- this._hiddenVar = 'webkitvisibilitychange';
- }
- else if (document.mozHidden !== undefined)
- {
- this._hiddenVar = 'mozvisibilitychange';
- }
- else if (document.msHidden !== undefined)
- {
- this._hiddenVar = 'msvisibilitychange';
- }
- else if (document.hidden !== undefined)
- {
- this._hiddenVar = 'visibilitychange';
- }
- else
- {
- this._hiddenVar = null;
- }
- // Does browser support it? If not (like in IE9 or old Android) we need to fall back to blur/focus
- if (this._hiddenVar)
- {
- document.addEventListener(this._hiddenVar, this._onChange, false);
- }
- window.onpagehide = this._onChange;
- window.onpageshow = this._onChange;
- window.onblur = this._onChange;
- window.onfocus = this._onChange;
- };
- /**
- * This method is called when the document visibility is changed.
- * @method Phaser.Stage#visibilityChange
- * @param {Event} event - Its type will be used to decide whether the game should be paused or not.
- */
- Phaser.Stage.prototype.visibilityChange = function (event) {
- if (this.disableVisibilityChange)
- {
- return;
- }
- if (event.type === 'pagehide' || event.type === 'blur' || event.type === 'pageshow' || event.type === 'focus')
- {
- if (event.type === 'pagehide' || event.type === 'blur')
- {
- this.game.focusLoss(event);
- }
- else if (event.type === 'pageshow' || event.type === 'focus')
- {
- this.game.focusGain(event);
- }
- return;
- }
- if (document.hidden || document.mozHidden || document.msHidden || document.webkitHidden)
- {
- this.game.gamePaused(event);
- }
- else
- {
- this.game.gameResumed(event);
- }
- };
- /**
- * Sets the background color for the stage.
- *
- * @name Phaser.Stage#setBackgroundColor
- * @param {number} backgroundColor - The color of the background, easiest way to pass this in is in hex format like: 0xFFFFFF for white.
- */
- Phaser.Stage.prototype.setBackgroundColor = function(backgroundColor)
- {
- this._backgroundColor = backgroundColor || 0x000000;
- this.backgroundColorSplit = PIXI.hex2rgb(this.backgroundColor);
- var hex = this._backgroundColor.toString(16);
- hex = '000000'.substr(0, 6 - hex.length) + hex;
- this.backgroundColorString = '#' + hex;
- };
- /**
- * @name Phaser.Stage#backgroundColor
- * @property {number|string} backgroundColor - Gets and sets the background color of the stage. The color can be given as a number: 0xff0000 or a hex string: '#ff0000'
- */
- Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", {
- get: function () {
- return this._backgroundColor;
- },
- set: function (color) {
- this._backgroundColor = color;
- if (this.game.transparent === false)
- {
- if (typeof color === 'string')
- {
- color = Phaser.Color.hexToRGB(color);
- }
- this.setBackgroundColor(color);
- }
- }
- });
- /**
- * Enable or disable texture smoothing for all objects on this Stage. Only works for bitmap/image textures. Smoothing is enabled by default.
- *
- * @name Phaser.Stage#smoothed
- * @property {boolean} smoothed - Set to true to smooth all sprites rendered on this Stage, or false to disable smoothing (great for pixel art)
- */
- Object.defineProperty(Phaser.Stage.prototype, "smoothed", {
- get: function () {
- return !PIXI.scaleModes.LINEAR;
- },
- set: function (value) {
- if (value)
- {
- PIXI.scaleModes.LINEAR = 0;
- }
- else
- {
- PIXI.scaleModes.LINEAR = 1;
- }
- }
- });
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * Phaser Group constructor.
- * @class Phaser.Group
- * @classdesc A Group is a container for display objects that allows for fast pooling and object recycling. Groups can be nested within other Groups and have their own local transforms.
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- * @param {Phaser.Group|Phaser.Sprite|null} parent - The parent Group, DisplayObject or DisplayObjectContainer that this Group will be added to. If undefined it will use game.world. If null it won't be added to anything.
- * @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging.
- * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
- * @param {boolean} [enableBody=false] - If true all Sprites created with `Group.create` or `Group.createMulitple` will have a physics body created on them. Change the body type with physicsBodyType.
- * @param {number} [physicsBodyType=0] - If enableBody is true this is the type of physics body that is created on new Sprites. Phaser.Physics.ARCADE, Phaser.Physics.P2, Phaser.Physics.NINJA, etc.
- */
- Phaser.Group = function (game, parent, name, addToStage, enableBody, physicsBodyType) {
- if (typeof addToStage === 'undefined') { addToStage = false; }
- if (typeof enableBody === 'undefined') { enableBody = false; }
- if (typeof physicsBodyType === 'undefined') { physicsBodyType = Phaser.Physics.ARCADE; }
- /**
- * @property {Phaser.Game} game - A reference to the currently running Game.
- */
- this.game = game;
- if (typeof parent === 'undefined')
- {
- parent = game.world;
- }
- /**
- * @property {string} name - A name for this Group. Not used internally but useful for debugging.
- */
- this.name = name || 'group';
- PIXI.DisplayObjectContainer.call(this);
- if (addToStage)
- {
- this.game.stage.addChild(this);
- }
- else
- {
- if (parent)
- {
- parent.addChild(this);
- }
- }
- /**
- * @property {number} z - The z-depth value of this object within its Group (remember the World is a Group as well). No two objects in a Group can have the same z value.
- */
- this.z = 0;
- /**
- * @property {number} type - Internal Phaser Type value.
- * @protected
- */
- this.type = Phaser.GROUP;
- /**
- * @property {boolean} alive - The alive property is useful for Groups that are children of other Groups and need to be included/excluded in checks like forEachAlive.
- * @default
- */
- this.alive = true;
- /**
- * @property {boolean} exists - If exists is true the Group is updated, otherwise it is skipped.
- * @default
- */
- this.exists = true;
- /**
- * @property {Phaser.Group|Phaser.Sprite} parent - The parent of this Group.
- */
- /**
- * @property {Phaser.Point} scale - The scale of the Group container.
- */
- this.scale = new Phaser.Point(1, 1);
- /**
- * @property {Phaser.Point} pivot - The pivot point of the Group container.
- */
- /**
- * The cursor is a simple way to iterate through the objects in a Group using the Group.next and Group.previous functions.
- * The cursor is set to the first child added to the Group and doesn't change unless you call next, previous or set it directly with Group.cursor.
- * @property {any} cursor - The current display object that the Group cursor is pointing to.
- */
- this.cursor = null;
- /**
- * @property {Phaser.Point} cameraOffset - If this object is fixedToCamera then this stores the x/y offset that its drawn at, from the top-left of the camera view.
- */
- this.cameraOffset = new Phaser.Point();
- /**
- * @property {boolean} enableBody - If true all Sprites created by, or added to this Group, will have a physics body enabled on them. Change the body type with `Group.physicsBodyType`.
- * @default
- */
- this.enableBody = enableBody;
- /**
- * @property {boolean} enableBodyDebug - If true when a physics body is created (via Group.enableBody) it will create a physics debug object as well. Only works for P2 bodies.
- */
- this.enableBodyDebug = false;
- /**
- * @property {number} physicsBodyType - If Group.enableBody is true this is the type of physics body that is created on new Sprites. Phaser.Physics.ARCADE, Phaser.Physics.P2, Phaser.Physics.NINJA, etc.
- */
- this.physicsBodyType = physicsBodyType;
- /**
- * @property {string} _sortProperty - The property on which children are sorted.
- * @private
- */
- this._sortProperty = 'z';
- /**
- * A small internal cache:
- * 0 = previous position.x
- * 1 = previous position.y
- * 2 = previous rotation
- * 3 = renderID
- * 4 = fresh? (0 = no, 1 = yes)
- * 5 = outOfBoundsFired (0 = no, 1 = yes)
- * 6 = exists (0 = no, 1 = yes)
- * 7 = fixed to camera (0 = no, 1 = yes)
- * 8 = cursor index
- * 9 = sort order
- * @property {Array} _cache
- * @private
- */
- this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 ];
- };
- Phaser.Group.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
- Phaser.Group.prototype.constructor = Phaser.Group;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Group.RETURN_NONE = 0;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Group.RETURN_TOTAL = 1;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Group.RETURN_CHILD = 2;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Group.SORT_ASCENDING = -1;
- /**
- * @constant
- * @type {number}
- */
- Phaser.Group.SORT_DESCENDING = 1;
- /**
- * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object.
- * The child is automatically added to the top of the Group, so renders on-top of everything else within the Group. If you need to control
- * that then see the addAt method.
- *
- * @see Phaser.Group#create
- * @see Phaser.Group#addAt
- * @method Phaser.Group#add
- * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object..
- * @return {*} The child that was added to the Group.
- */
- Phaser.Group.prototype.add = function (child) {
- if (child.parent !== this)
- {
- if (this.enableBody)
- {
- this.game.physics.enable(child, this.physicsBodyType);
- }
- this.addChild(child);
- child.z = this.children.length;
- if (child.events)
- {
- child.events.onAddedToGroup.dispatch(child, this);
- }
- if (this.cursor === null)
- {
- this.cursor = child;
- }
- }
- return child;
- };
- /**
- * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object.
- * The child is added to the Group at the location specified by the index value, this allows you to control child ordering.
- *
- * @method Phaser.Group#addAt
- * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object..
- * @param {number} index - The index within the Group to insert the child to.
- * @return {*} The child that was added to the Group.
- */
- Phaser.Group.prototype.addAt = function (child, index) {
- if (child.parent !== this)
- {
- if (this.enableBody)
- {
- this.game.physics.enable(child, this.physicsBodyType);
- }
- this.addChildAt(child, index);
- this.updateZ();
- if (child.events)
- {
- child.events.onAddedToGroup.dispatch(child, this);
- }
- if (this.cursor === null)
- {
- this.cursor = child;
- }
- }
- return child;
- };
- /**
- * Returns the child found at the given index within this Group.
- *
- * @method Phaser.Group#getAt
- * @param {number} index - The index to return the child from.
- * @return {*} The child that was found at the given index. If the index was out of bounds then this will return -1.
- */
- Phaser.Group.prototype.getAt = function (index) {
- if (index < 0 || index >= this.children.length)
- {
- return -1;
- }
- else
- {
- return this.getChildAt(index);
- }
- };
- /**
- * Automatically creates a new Phaser.Sprite object and adds it to the top of this Group.
- * Useful if you don't need to create the Sprite instances before-hand.
- *
- * @method Phaser.Group#create
- * @param {number} x - The x coordinate to display the newly created Sprite at. The value is in relation to the Group.x point.
- * @param {number} y - The y coordinate to display the newly created Sprite at. The value is in relation to the Group.y point.
- * @param {string} key - The Game.cache key of the image that this Sprite will use.
- * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
- * @param {boolean} [exists=true] - The default exists state of the Sprite.
- * @return {Phaser.Sprite} The child that was created.
- */
- Phaser.Group.prototype.create = function (x, y, key, frame, exists) {
- if (typeof exists === 'undefined') { exists = true; }
- var child = new Phaser.Sprite(this.game, x, y, key, frame);
- if (this.enableBody)
- {
- this.game.physics.enable(child, this.physicsBodyType);
- }
- child.exists = exists;
- child.visible = exists;
- child.alive = exists;
- this.addChild(child);
- child.z = this.children.length;
- if (child.events)
- {
- child.events.onAddedToGroup.dispatch(child, this);
- }
- if (this.cursor === null)
- {
- this.cursor = child;
- }
- return child;
- };
- /**
- * Automatically creates multiple Phaser.Sprite objects and adds them to the top of this Group.
- * Useful if you need to quickly generate a pool of identical sprites, such as bullets. By default the sprites will be set to not exist
- * and will be positioned at 0, 0 (relative to the Group.x/y)
- *
- * @method Phaser.Group#createMultiple
- * @param {number} quantity - The number of Sprites to create.
- * @param {string} key - The Game.cache key of the image that this Sprite will use.
- * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
- * @param {boolean} [exists=false] - The default exists state of the Sprite.
- */
- Phaser.Group.prototype.createMultiple = function (quantity, key, frame, exists) {
- if (typeof exists === 'undefined') { exists = false; }
- for (var i = 0; i < quantity; i++)
- {
- this.create(0, 0, key, frame, exists);
- }
- };
- /**
- * Internal method that re-applies all of the childrens Z values.
- *
- * @method Phaser.Group#updateZ
- * @protected
- */
- Phaser.Group.prototype.updateZ = function () {
- var i = this.children.length;
- while (i--)
- {
- this.children[i].z = i;
- }
- };
- /**
- * Advances the Group cursor to the next object in the Group. If it's at the end of the Group it wraps around to the first object.
- *
- * @method Phaser.Group#next
- * @return {*} The child the cursor now points to.
- */
- Phaser.Group.prototype.next = function () {
- if (this.cursor)
- {
- // Wrap the cursor?
- if (this._cache[8] >= this.children.length - 1)
- {
- this._cache[8] = 0;
- }
- else
- {
- this._cache[8]++;
- }
- this.cursor = this.children[this._cache[8]];
- return this.cursor;
- }
- };
- /**
- * Moves the Group cursor to the previous object in the Group. If it's at the start of the Group it wraps around to the last object.
- *
- * @method Phaser.Group#previous
- * @return {*} The child the cursor now points to.
- */
- Phaser.Group.prototype.previous = function () {
- if (this.cursor)
- {
- // Wrap the cursor?
- if (this._cache[8] === 0)
- {
- this._cache[8] = this.children.length - 1;
- }
- else
- {
- this._cache[8]--;
- }
- this.cursor = this.children[this._cache[8]];
- return this.cursor;
- }
- };
- /**
- * Swaps the position of two children in this Group. Both children must be in this Group.
- * You cannot swap a child with itself, or swap un-parented children, doing so will return false.
- *
- * @method Phaser.Group#swap
- * @param {*} child1 - The first child to swap.
- * @param {*} child2 - The second child to swap.
- */
- Phaser.Group.prototype.swap = function (child1, child2) {
- var result = this.swapChildren(child1, child2);
- if (result)
- {
- this.updateZ();
- }
- return result;
- };
- /**
- * Brings the given child to the top of this Group so it renders above all other children.
- *
- * @method Phaser.Group#bringToTop
- * @param {*} child - The child to bring to the top of this Group.
- * @return {*} The child that was moved.
- */
- Phaser.Group.prototype.bringToTop = function (child) {
- if (child.parent === this && this.getIndex(child) < this.children.length)
- {
- this.remove(child);
- this.add(child);
- }
- return child;
- };
- /**
- * Sends the given child to the bottom of this Group so it renders below all other children.
- *
- * @method Phaser.Group#sendToBack
- * @param {*} child - The child to send to the bottom of this Group.
- * @return {*} The child that was moved.
- */
- Phaser.Group.prototype.sendToBack = function (child) {
- if (child.parent === this && this.getIndex(child) > 0)
- {
- this.remove(child);
- this.addAt(child, 0);
- }
- return child;
- };
- /**
- * Moves the given child up one place in this Group unless it's already at the top.
- *
- * @method Phaser.Group#moveUp
- * @param {*} child - The child to move up in the Group.
- * @return {*} The child that was moved.
- */
- Phaser.Group.prototype.moveUp = function (child) {
- if (child.parent === this && this.getIndex(child) < this.children.length - 1)
- {
- var a = this.getIndex(child);
- var b = this.getAt(a + 1);
- if (b)
- {
- this.swap(child, b);
- }
- }
- return child;
- };
- /**
- * Moves the given child down one place in this Group unless it's already at the top.
- *
- * @method Phaser.Group#moveDown
- * @param {*} child - The child to move down in the Group.
- * @return {*} The child that was moved.
- */
- Phaser.Group.prototype.moveDown = function (child) {
- if (child.parent === this && this.getIndex(child) > 0)
- {
- var a = this.getIndex(child);
- var b = this.getAt(a - 1);
- if (b)
- {
- this.swap(child, b);
- }
- }
- return child;
- };
- /**
- * Positions the child found at the given index within this Group to the given x and y coordinates.
- *
- * @method Phaser.Group#xy
- * @param {number} index - The index of the child in the Group to set the position of.
- * @param {number} x - The new x position of the child.
- * @param {number} y - The new y position of the child.
- */
- Phaser.Group.prototype.xy = function (index, x, y) {
- if (index < 0 || index > this.children.length)
- {
- return -1;
- }
- else
- {
- this.getChildAt(index).x = x;
- this.getChildAt(index).y = y;
- }
- };
- /**
- * Reverses all children in this Group. Note that this does not propagate, only direct children are re-ordered.
- *
- * @method Phaser.Group#reverse
- */
- Phaser.Group.prototype.reverse = function () {
- this.children.reverse();
- this.updateZ();
- };
- /**
- * Get the index position of the given child in this Group. This should always match the childs z property.
- *
- * @method Phaser.Group#getIndex
- * @param {*} child - The child to get the index for.
- * @return {number} The index of the child or -1 if it's not a member of this Group.
- */
- Phaser.Group.prototype.getIndex = function (child) {
- return this.children.indexOf(child);
- };
- /**
- * Replaces a child of this Group with the given newChild. The newChild cannot be a member of this Group.
- *
- * @method Phaser.Group#replace
- * @param {*} oldChild - The child in this Group that will be replaced.
- * @param {*} newChild - The child to be inserted into this Group.
- * @return {*} Returns the oldChild that was replaced within this Group.
- */
- Phaser.Group.prototype.replace = function (oldChild, newChild) {
- var index = this.getIndex(oldChild);
- if (index !== -1)
- {
- if (newChild.parent !== undefined)
- {
- newChild.events.onRemovedFromGroup.dispatch(newChild, this);
- newChild.parent.removeChild(newChild);
- if (newChild.parent instanceof Phaser.Group)
- {
- newChild.parent.updateZ();
- }
- }
- var temp = oldChild;
- this.remove(temp);
- this.addAt(newChild, index);
- return temp;
- }
- };
- /**
- * Sets the given property to the given value on the child. The operation controls the assignment of the value.
- *
- * @method Phaser.Group#setProperty
- * @param {*} child - The child to set the property value on.
- * @param {array} key - An array of strings that make up the property that will be set.
- * @param {*} value - The value that will be set.
- * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
- */
- Phaser.Group.prototype.setProperty = function (child, key, value, operation) {
- operation = operation || 0;
- // As ugly as this approach looks, and although it's limited to a depth of only 4, it's extremely fast.
- // Much faster than a for loop or object iteration. There are no checks, so if the key isn't valid then it'll fail
- // but as you are likely to call this from inner loops that have to perform well, I'll take that trade off.
- // 0 = Equals
- // 1 = Add
- // 2 = Subtract
- // 3 = Multiply
- // 4 = Divide
- var len = key.length;
- if (len == 1)
- {
- if (operation === 0) { child[key[0]] = value; }
- else if (operation == 1) { child[key[0]] += value; }
- else if (operation == 2) { child[key[0]] -= value; }
- else if (operation == 3) { child[key[0]] *= value; }
- else if (operation == 4) { child[key[0]] /= value; }
- }
- else if (len == 2)
- {
- if (operation === 0) { child[key[0]][key[1]] = value; }
- else if (operation == 1) { child[key[0]][key[1]] += value; }
- else if (operation == 2) { child[key[0]][key[1]] -= value; }
- else if (operation == 3) { child[key[0]][key[1]] *= value; }
- else if (operation == 4) { child[key[0]][key[1]] /= value; }
- }
- else if (len == 3)
- {
- if (operation === 0) { child[key[0]][key[1]][key[2]] = value; }
- else if (operation == 1) { child[key[0]][key[1]][key[2]] += value; }
- else if (operation == 2) { child[key[0]][key[1]][key[2]] -= value; }
- else if (operation == 3) { child[key[0]][key[1]][key[2]] *= value; }
- else if (operation == 4) { child[key[0]][key[1]][key[2]] /= value; }
- }
- else if (len == 4)
- {
- if (operation === 0) { child[key[0]][key[1]][key[2]][key[3]] = value; }
- else if (operation == 1) { child[key[0]][key[1]][key[2]][key[3]] += value; }
- else if (operation == 2) { child[key[0]][key[1]][key[2]][key[3]] -= value; }
- else if (operation == 3) { child[key[0]][key[1]][key[2]][key[3]] *= value; }
- else if (operation == 4) { child[key[0]][key[1]][key[2]][key[3]] /= value; }
- }
- };
- /**
- * This function allows you to quickly set a property on a single child of this Group to a new value.
- * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
- *
- * @method Phaser.Group#set
- * @param {Phaser.Sprite} child - The child to set the property on.
- * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
- * @param {*} value - The value that will be set.
- * @param {boolean} [checkAlive=false] - If set then the child will only be updated if alive=true.
- * @param {boolean} [checkVisible=false] - If set then the child will only be updated if visible=true.
- * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
- */
- Phaser.Group.prototype.set = function (child, key, value, checkAlive, checkVisible, operation) {
- key = key.split('.');
- if (typeof checkAlive === 'undefined') { checkAlive = false; }
- if (typeof checkVisible === 'undefined') { checkVisible = false; }
- if ((checkAlive === false || (checkAlive && child.alive)) && (checkVisible === false || (checkVisible && child.visible)))
- {
- this.setProperty(child, key, value, operation);
- }
- };
- /**
- * This function allows you to quickly set the same property across all children of this Group to a new value.
- * This call doesn't descend down children, so if you have a Group inside of this Group, the property will be set on the Group but not its children.
- * If you need that ability please see `Group.setAllChildren`.
- *
- * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
- *
- * @method Phaser.Group#setAll
- * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
- * @param {*} value - The value that will be set.
- * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
- * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
- * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
- */
- Phaser.Group.prototype.setAll = function (key, value, checkAlive, checkVisible, operation) {
- key = key.split('.');
- if (typeof checkAlive === 'undefined') { checkAlive = false; }
- if (typeof checkVisible === 'undefined') { checkVisible = false; }
- operation = operation || 0;
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
- {
- this.setProperty(this.children[i], key, value, operation);
- }
- }
- };
- /**
- * This function allows you to quickly set the same property across all children of this Group, and any child Groups, to a new value.
- *
- * If this Group contains other Groups then the same property is set across their children as well, iterating down until it reaches the bottom.
- * Unlike with Group.setAll the property is NOT set on child Groups itself.
- *
- * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
- *
- * @method Phaser.Group#setAllChildren
- * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
- * @param {*} value - The value that will be set.
- * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
- * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
- * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
- */
- Phaser.Group.prototype.setAllChildren = function (key, value, checkAlive, checkVisible, operation) {
- if (typeof checkAlive === 'undefined') { checkAlive = false; }
- if (typeof checkVisible === 'undefined') { checkVisible = false; }
- operation = operation || 0;
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
- {
- if (this.children[i] instanceof Phaser.Group)
- {
- this.children[i].setAllChildren(key, value, checkAlive, checkVisible, operation);
- }
- else
- {
- this.setProperty(this.children[i], key.split('.'), value, operation);
- }
- }
- }
- };
- /**
- * Adds the amount to the given property on all children in this Group.
- * Group.addAll('x', 10) will add 10 to the child.x value.
- *
- * @method Phaser.Group#addAll
- * @param {string} property - The property to increment, for example 'body.velocity.x' or 'angle'.
- * @param {number} amount - The amount to increment the property by. If child.x = 10 then addAll('x', 40) would make child.x = 50.
- * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
- * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
- */
- Phaser.Group.prototype.addAll = function (property, amount, checkAlive, checkVisible) {
- this.setAll(property, amount, checkAlive, checkVisible, 1);
- };
- /**
- * Subtracts the amount from the given property on all children in this Group.
- * Group.subAll('x', 10) will minus 10 from the child.x value.
- *
- * @method Phaser.Group#subAll
- * @param {string} property - The property to decrement, for example 'body.velocity.x' or 'angle'.
- * @param {number} amount - The amount to subtract from the property. If child.x = 50 then subAll('x', 40) would make child.x = 10.
- * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
- * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
- */
- Phaser.Group.prototype.subAll = function (property, amount, checkAlive, checkVisible) {
- this.setAll(property, amount, checkAlive, checkVisible, 2);
- };
- /**
- * Multiplies the given property by the amount on all children in this Group.
- * Group.multiplyAll('x', 2) will x2 the child.x value.
- *
- * @method Phaser.Group#multiplyAll
- * @param {string} property - The property to multiply, for example 'body.velocity.x' or 'angle'.
- * @param {number} amount - The amount to multiply the property by. If child.x = 10 then multiplyAll('x', 2) would make child.x = 20.
- * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
- * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
- */
- Phaser.Group.prototype.multiplyAll = function (property, amount, checkAlive, checkVisible) {
- this.setAll(property, amount, checkAlive, checkVisible, 3);
- };
- /**
- * Divides the given property by the amount on all children in this Group.
- * Group.divideAll('x', 2) will half the child.x value.
- *
- * @method Phaser.Group#divideAll
- * @param {string} property - The property to divide, for example 'body.velocity.x' or 'angle'.
- * @param {number} amount - The amount to divide the property by. If child.x = 100 then divideAll('x', 2) would make child.x = 50.
- * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
- * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
- */
- Phaser.Group.prototype.divideAll = function (property, amount, checkAlive, checkVisible) {
- this.setAll(property, amount, checkAlive, checkVisible, 4);
- };
- /**
- * Calls a function on all of the children that have exists=true in this Group.
- * After the existsValue parameter you can add as many parameters as you like, which will all be passed to the child callback.
- *
- * @method Phaser.Group#callAllExists
- * @param {function} callback - The function that exists on the children that will be called.
- * @param {boolean} existsValue - Only children with exists=existsValue will be called.
- * @param {...*} parameter - Additional parameters that will be passed to the callback.
- */
- Phaser.Group.prototype.callAllExists = function (callback, existsValue) {
- var args = Array.prototype.splice.call(arguments, 2);
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- if (this.children[i].exists === existsValue && this.children[i][callback])
- {
- this.children[i][callback].apply(this.children[i], args);
- }
- }
- };
- /**
- * Returns a reference to a function that exists on a child of the Group based on the given callback array.
- *
- * @method Phaser.Group#callbackFromArray
- * @param {object} child - The object to inspect.
- * @param {array} callback - The array of function names.
- * @param {number} length - The size of the array (pre-calculated in callAll).
- * @protected
- */
- Phaser.Group.prototype.callbackFromArray = function (child, callback, length) {
- // Kinda looks like a Christmas tree
- if (length == 1)
- {
- if (child[callback[0]])
- {
- return child[callback[0]];
- }
- }
- else if (length == 2)
- {
- if (child[callback[0]][callback[1]])
- {
- return child[callback[0]][callback[1]];
- }
- }
- else if (length == 3)
- {
- if (child[callback[0]][callback[1]][callback[2]])
- {
- return child[callback[0]][callback[1]][callback[2]];
- }
- }
- else if (length == 4)
- {
- if (child[callback[0]][callback[1]][callback[2]][callback[3]])
- {
- return child[callback[0]][callback[1]][callback[2]][callback[3]];
- }
- }
- else
- {
- if (child[callback])
- {
- return child[callback];
- }
- }
- return false;
- };
- /**
- * Calls a function on all of the children regardless if they are dead or alive (see callAllExists if you need control over that)
- * After the method parameter and context you can add as many extra parameters as you like, which will all be passed to the child.
- *
- * @method Phaser.Group#callAll
- * @param {string} method - A string containing the name of the function that will be called. The function must exist on the child.
- * @param {string} [context=null] - A string containing the context under which the method will be executed. Set to null to default to the child.
- * @param {...*} parameter - Additional parameters that will be passed to the method.
- */
- Phaser.Group.prototype.callAll = function (method, context) {
- if (typeof method === 'undefined')
- {
- return;
- }
- // Extract the method into an array
- method = method.split('.');
- var methodLength = method.length;
- if (typeof context === 'undefined' || context === null || context === '')
- {
- context = null;
- }
- else
- {
- // Extract the context into an array
- if (typeof context === 'string')
- {
- context = context.split('.');
- var contextLength = context.length;
- }
- }
- var args = Array.prototype.splice.call(arguments, 2);
- var callback = null;
- var callbackContext = null;
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- callback = this.callbackFromArray(this.children[i], method, methodLength);
- if (context && callback)
- {
- callbackContext = this.callbackFromArray(this.children[i], context, contextLength);
- if (callback)
- {
- callback.apply(callbackContext, args);
- }
- }
- else if (callback)
- {
- callback.apply(this.children[i], args);
- }
- }
- };
- /**
- * The core preUpdate - as called by World.
- * @method Phaser.Group#preUpdate
- * @protected
- */
- Phaser.Group.prototype.preUpdate = function () {
- if (!this.exists || !this.parent.exists)
- {
- this.renderOrderID = -1;
- return false;
- }
- var i = this.children.length;
- while (i--)
- {
- this.children[i].preUpdate();
- }
- return true;
- };
- /**
- * The core update - as called by World.
- * @method Phaser.Group#update
- * @protected
- */
- Phaser.Group.prototype.update = function () {
- var i = this.children.length;
- while (i--)
- {
- this.children[i].update();
- }
- };
- /**
- * The core postUpdate - as called by World.
- * @method Phaser.Group#postUpdate
- * @protected
- */
- Phaser.Group.prototype.postUpdate = function () {
- // Fixed to Camera?
- if (this._cache[7] === 1)
- {
- this.x = this.game.camera.view.x + this.cameraOffset.x;
- this.y = this.game.camera.view.y + this.cameraOffset.y;
- }
- var i = this.children.length;
- while (i--)
- {
- this.children[i].postUpdate();
- }
- };
- /**
- * Allows you to call your own function on each member of this Group. You must pass the callback and context in which it will run.
- * After the checkExists parameter you can add as many parameters as you like, which will all be passed to the callback along with the child.
- * For example: Group.forEach(awardBonusGold, this, true, 100, 500)
- * Note: Currently this will skip any children which are Groups themselves.
- *
- * @method Phaser.Group#forEach
- * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
- * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
- * @param {boolean} [checkExists=false] - If set only children with exists=true will be passed to the callback, otherwise all children will be passed.
- */
- Phaser.Group.prototype.forEach = function (callback, callbackContext, checkExists) {
- if (typeof checkExists === 'undefined') { checkExists = false; }
- var args = Array.prototype.splice.call(arguments, 3);
- args.unshift(null);
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- if (!checkExists || (checkExists && this.children[i].exists))
- {
- args[0] = this.children[i];
- callback.apply(callbackContext, args);
- }
- }
- };
- /**
- * Allows you to call your own function on each member of this Group where child.exists=true. You must pass the callback and context in which it will run.
- * You can add as many parameters as you like, which will all be passed to the callback along with the child.
- * For example: Group.forEachExists(causeDamage, this, 500)
- *
- * @method Phaser.Group#forEachExists
- * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
- * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
- */
- Phaser.Group.prototype.forEachExists = function (callback, callbackContext) {
- var args = Array.prototype.splice.call(arguments, 2);
- args.unshift(null);
- this.iterate('exists', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
- };
- /**
- * Allows you to call your own function on each alive member of this Group (where child.alive=true). You must pass the callback and context in which it will run.
- * You can add as many parameters as you like, which will all be passed to the callback along with the child.
- * For example: Group.forEachAlive(causeDamage, this, 500)
- *
- * @method Phaser.Group#forEachAlive
- * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
- * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
- */
- Phaser.Group.prototype.forEachAlive = function (callback, callbackContext) {
- var args = Array.prototype.splice.call(arguments, 2);
- args.unshift(null);
- this.iterate('alive', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
- };
- /**
- * Allows you to call your own function on each dead member of this Group (where alive=false). You must pass the callback and context in which it will run.
- * You can add as many parameters as you like, which will all be passed to the callback along with the child.
- * For example: Group.forEachDead(bringToLife, this)
- *
- * @method Phaser.Group#forEachDead
- * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
- * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
- */
- Phaser.Group.prototype.forEachDead = function (callback, callbackContext) {
- var args = Array.prototype.splice.call(arguments, 2);
- args.unshift(null);
- this.iterate('alive', false, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
- };
- /**
- * Call this function to sort the group according to a particular value and order.
- * For example to depth sort Sprites for Zelda-style game you might call `group.sort('y', Phaser.Group.SORT_ASCENDING)` at the bottom of your `State.update()`.
- *
- * @method Phaser.Group#sort
- * @param {string} [index='z'] - The `string` name of the property you want to sort on. Defaults to the objects z-depth value.
- * @param {number} [order=Phaser.Group.SORT_ASCENDING] - The `Group` constant that defines the sort order. Possible values are Phaser.Group.SORT_ASCENDING and Phaser.Group.SORT_DESCENDING.
- */
- Phaser.Group.prototype.sort = function (index, order) {
- if (this.children.length < 2)
- {
- // Nothing to swap
- return;
- }
- if (typeof index === 'undefined') { index = 'z'; }
- if (typeof order === 'undefined') { order = Phaser.Group.SORT_ASCENDING; }
- this._sortProperty = index;
- if (order === Phaser.Group.SORT_ASCENDING)
- {
- this.children.sort(this.ascendingSortHandler.bind(this));
- }
- else
- {
- this.children.sort(this.descendingSortHandler.bind(this));
- }
- this.updateZ();
- };
- /**
- * This allows you to use your own sort handler function.
- * It will be sent two parameters: the two children involved in the comparison (a and b). It should return -1 if a > b, 1 if a < b or 0 if a === b.
- *
- * @method Phaser.Group#customSort
- * @param {function} sortHandler - Your sort handler function. It will be sent two parameters: the two children involved in the comparison. It must return -1, 1 or 0.
- * @param {object} context - The scope in which the sortHandler is called.
- */
- Phaser.Group.prototype.customSort = function (sortHandler, context) {
- if (this.children.length < 2)
- {
- // Nothing to swap
- return;
- }
- this.children.sort(sortHandler.bind(context));
- this.updateZ();
- };
- /**
- * An internal helper function for the sort process.
- *
- * @method Phaser.Group#ascendingSortHandler
- * @param {object} a - The first object being sorted.
- * @param {object} b - The second object being sorted.
- */
- Phaser.Group.prototype.ascendingSortHandler = function (a, b) {
- if (a[this._sortProperty] < b[this._sortProperty])
- {
- return -1;
- }
- else if (a[this._sortProperty] > b[this._sortProperty])
- {
- return 1;
- }
- else
- {
- if (a.z < b.z)
- {
- return -1;
- }
- else
- {
- return 1;
- }
- }
- };
- /**
- * An internal helper function for the sort process.
- *
- * @method Phaser.Group#descendingSortHandler
- * @param {object} a - The first object being sorted.
- * @param {object} b - The second object being sorted.
- */
- Phaser.Group.prototype.descendingSortHandler = function (a, b) {
- if (a[this._sortProperty] < b[this._sortProperty])
- {
- return 1;
- }
- else if (a[this._sortProperty] > b[this._sortProperty])
- {
- return -1;
- }
- else
- {
- return 0;
- }
- };
- /**
- * Iterates over the children of the Group. When a child has a property matching key that equals the given value, it is considered as a match.
- * Matched children can be sent to the optional callback, or simply returned or counted.
- * You can add as many callback parameters as you like, which will all be passed to the callback along with the child, after the callbackContext parameter.
- *
- * @method Phaser.Group#iterate
- * @param {string} key - The child property to check, i.e. 'exists', 'alive', 'health'
- * @param {any} value - If child.key === this value it will be considered a match. Note that a strict comparison is used.
- * @param {number} returnType - How to return the data from this method. Either Phaser.Group.RETURN_NONE, Phaser.Group.RETURN_TOTAL or Phaser.Group.RETURN_CHILD.
- * @param {function} [callback=null] - Optional function that will be called on each matching child. Each child of the Group will be passed to it as its first parameter.
- * @param {Object} [callbackContext] - The context in which the function should be called (usually 'this').
- * @return {any} Returns either a numeric total (if RETURN_TOTAL was specified) or the child object.
- */
- Phaser.Group.prototype.iterate = function (key, value, returnType, callback, callbackContext, args) {
- if (returnType === Phaser.Group.RETURN_TOTAL && this.children.length === 0)
- {
- return 0;
- }
- if (typeof callback === 'undefined')
- {
- callback = false;
- }
- var total = 0;
- for (var i = 0, len = this.children.length; i < len; i++)
- {
- if (this.children[i][key] === value)
- {
- total++;
- if (callback)
- {
- args[0] = this.children[i];
- callback.apply(callbackContext, args);
- }
- if (returnType === Phaser.Group.RETURN_CHILD)
- {
- return this.children[i];
- }
- }
- }
- if (returnType === Phaser.Group.RETURN_TOTAL)
- {
- return total;
- }
- else if (returnType === Phaser.Group.RETURN_CHILD)
- {
- return null;
- }
- };
- /**
- * Call this function to retrieve the first object with exists == (the given state) in the Group.
- *
- * @method Phaser.Group#getFirstExists
- * @param {boolean} state - True or false.
- * @return {Any} The first child, or null if none found.
- */
- Phaser.Group.prototype.getFirstExists = function (state) {
- if (typeof state !== 'boolean')
- {
- state = true;
- }
- return this.iterate('exists', state, Phaser.Group.RETURN_CHILD);
- };
- /**
- * Call this function to retrieve the first object with alive === true in the group.
- * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc.
- *
- * @method Phaser.Group#getFirstAlive
- * @return {Any} The first alive child, or null if none found.
- */
- Phaser.Group.prototype.getFirstAlive = function () {
- return this.iterate('alive', true, Phaser.Group.RETURN_CHILD);
- };
- /**
- * Call this function to retrieve the first object with alive === false in the group.
- * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc.
- *
- * @method Phaser.Group#getFirstDead
- * @return {Any} The first dead child, or null if none found.
- */
- Phaser.Group.prototype.getFirstDead = function () {
- return this.iterate('alive', false, Phaser.Group.RETURN_CHILD);
- };
- /**
- * Returns the child at the top of this Group. The top is the one being displayed (rendered) above every other child.
- *
- * @method Phaser.Group#getTop
- * @return {Any} The child at the top of the Group.
- */
- Phaser.Group.prototype.getTop = function () {
- if (this.children.length > 0)
- {
- return this.children[this.children.length - 1];
- }
- };
- /**
- * Returns the child at the bottom of this Group. The bottom is the one being displayed (rendered) below every other child.
- *
- * @method Phaser.Group#getBottom
- * @return {Any} The child at the bottom of the Group.
- */
- Phaser.Group.prototype.getBottom = function () {
- if (this.children.length > 0)
- {
- return this.children[0];
- }
- };
- /**
- * Call this function to find out how many members of the group are alive.
- *
- * @method Phaser.Group#countLiving
- * @return {number} The number of children flagged as alive.
- */
- Phaser.Group.prototype.countLiving = function () {
- return this.iterate('alive', true, Phaser.Group.RETURN_TOTAL);
- };
- /**
- * Call this function to find out how many members of the group are dead.
- *
- * @method Phaser.Group#countDead
- * @return {number} The number of children flagged as dead.
- */
- Phaser.Group.prototype.countDead = function () {
- return this.iterate('alive', false, Phaser.Group.RETURN_TOTAL);
- };
- /**
- * Returns a member at random from the group.
- *
- * @method Phaser.Group#getRandom
- * @param {number} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array.
- * @param {number} length - Optional restriction on the number of values you want to randomly select from.
- * @return {Any} A random child of this Group.
- */
- Phaser.Group.prototype.getRandom = function (startIndex, length) {
- if (this.children.length === 0)
- {
- return null;
- }
- startIndex = startIndex || 0;
- length = length || this.children.length;
- return this.game.math.getRandom(this.children, startIndex, length);
- };
- /**
- * Removes the given child from this Group and sets its group property to null.
- *
- * @method Phaser.Group#remove
- * @param {Any} child - The child to remove.
- * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
- * @return {boolean} true if the child was removed from this Group, otherwise false.
- */
- Phaser.Group.prototype.remove = function (child, destroy) {
- if (typeof destroy === 'undefined') { destroy = false; }
- if (this.children.length === 0)
- {
- return false;
- }
- if (child.events)
- {
- child.events.onRemovedFromGroup.dispatch(child, this);
- }
- this.removeChild(child);
- this.updateZ();
- if (this.cursor === child)
- {
- this.next();
- }
- if (destroy)
- {
- child.destroy();
- }
- return true;
- };
- /**
- * Removes all children from this Group, setting all group properties to null.
- * The Group container remains on the display list.
- *
- * @method Phaser.Group#removeAll
- * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
- */
- Phaser.Group.prototype.removeAll = function (destroy) {
- if (typeof destroy === 'undefined') { destroy = false; }
- if (this.children.length === 0)
- {
- return;
- }
- do
- {
- if (this.children[0].events)
- {
- this.children[0].events.onRemovedFromGroup.dispatch(this.children[0], this);
- }
- this.removeChild(this.children[0]);
- if (destroy)
- {
- this.children[0].destroy();
- }
- }
- while (this.children.length > 0);
- this.cursor = null;
- };
- /**
- * Removes all children from this Group whos index falls beteen the given startIndex and endIndex values.
- *
- * @method Phaser.Group#removeBetween
- * @param {number} startIndex - The index to start removing children from.
- * @param {number} [endIndex] - The index to stop removing children at. Must be higher than startIndex. If undefined this method will remove all children between startIndex and the end of the Group.
- * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
- */
- Phaser.Group.prototype.removeBetween = function (startIndex, endIndex, destroy) {
- if (typeof endIndex === 'undefined') { endIndex = this.children.length; }
- if (typeof destroy === 'undefined') { destroy = false; }
- if (this.children.length === 0)
- {
- return;
- }
- if (startIndex > endIndex || startIndex < 0 || endIndex > this.children.length)
- {
- return false;
- }
- var i = endIndex;
- while (i >= startIndex)
- {
- if (this.children[i].events)
- {
- this.children[i].events.onRemovedFromGroup.dispatch(this.children[i], this);
- }
- this.removeChild(this.children[i]);
- if (destroy)
- {
- this.children[i].destroy();
- }
- if (this.cursor === this.children[i])
- {
- this.cursor = null;
- }
- i--;
- }
- this.updateZ();
- };
- /**
- * Destroys this Group. Removes all children, then removes the container from the display list and nulls references.
- *
- * @method Phaser.Group#destroy
- * @param {boolean} [destroyChildren=true] - Should every child of this Group have its destroy method called?
- * @param {boolean} [soft=false] - A 'soft destroy' (set to true) doesn't remove this Group from its parent or null the game reference. Set to false and it does.
- */
- Phaser.Group.prototype.destroy = function (destroyChildren, soft) {
- if (this.game === null) { return; }
- if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
- if (typeof soft === 'undefined') { soft = false; }
- if (destroyChildren)
- {
- if (this.children.length > 0)
- {
- do
- {
- if (this.children[0].parent)
- {
- this.children[0].destroy(destroyChildren);
- }
- }
- while (this.children.length > 0);
- }
- }
- else
- {
- this.removeAll();
- }
- this.cursor = null;
- if (!soft)
- {
- this.parent.removeChild(this);
- this.game = null;
- this.exists = false;
- }
- };
- /**
- * @name Phaser.Group#total
- * @property {number} total - The total number of children in this Group who have a state of exists = true.
- * @readonly
- */
- Object.defineProperty(Phaser.Group.prototype, "total", {
- get: function () {
- return this.iterate('exists', true, Phaser.Group.RETURN_TOTAL);
- }
- });
- /**
- * @name Phaser.Group#length
- * @property {number} length - The total number of children in this Group, regardless of their exists/alive status.
- * @readonly
- */
- Object.defineProperty(Phaser.Group.prototype, "length", {
- get: function () {
- return this.children.length;
- }
- });
- /**
- * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation.
- * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position.
- * @name Phaser.Group#angle
- * @property {number} angle - The angle of rotation given in degrees, where 0 degrees = to the right.
- */
- Object.defineProperty(Phaser.Group.prototype, "angle", {
- get: function() {
- return Phaser.Math.radToDeg(this.rotation);
- },
- set: function(value) {
- this.rotation = Phaser.Math.degToRad(value);
- }
- });
- /**
- * A Group that is fixed to the camera uses its x/y coordinates as offsets from the top left of the camera. These are stored in Group.cameraOffset.
- * Note that the cameraOffset values are in addition to any parent in the display list.
- * So if this Group was in a Group that has x: 200, then this will be added to the cameraOffset.x
- *
- * @name Phaser.Group#fixedToCamera
- * @property {boolean} fixedToCamera - Set to true to fix this Group to the Camera at its current world coordinates.
- */
- Object.defineProperty(Phaser.Group.prototype, "fixedToCamera", {
- get: function () {
- return !!this._cache[7];
- },
- set: function (value) {
- if (value)
- {
- this._cache[7] = 1;
- this.cameraOffset.set(this.x, this.y);
- }
- else
- {
- this._cache[7] = 0;
- }
- }
- });
- // Documentation stubs
- /**
- * The x coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates.
- * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
- * @name Phaser.Group#x
- * @property {number} x - The x coordinate of the Group container.
- */
- /**
- * The y coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates.
- * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
- * @name Phaser.Group#y
- * @property {number} y - The y coordinate of the Group container.
- */
- /**
- * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation.
- * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position.
- * @name Phaser.Group#rotation
- * @property {number} rotation - The angle of rotation given in radians.
- */
- /**
- * @name Phaser.Group#visible
- * @property {boolean} visible - The visible state of the Group. Non-visible Groups and all of their children are not rendered.
- */
- /**
- * @name Phaser.Group#alpha
- * @property {number} alpha - The alpha value of the Group container.
- */
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * "This world is but a canvas to our imagination." - Henry David Thoreau
- *
- * A game has only one world. The world is an abstract place in which all game objects live. It is not bound
- * by stage limits and can be any size. You look into the world via cameras. All game objects live within
- * the world at world-based coordinates. By default a world is created the same size as your Stage.
- *
- * @class Phaser.World
- * @extends Phaser.Group
- * @constructor
- * @param {Phaser.Game} game - Reference to the current game instance.
- */
- Phaser.World = function (game) {
- Phaser.Group.call(this, game, null, '__world', false);
- /**
- * The World has no fixed size, but it does have a bounds outside of which objects are no longer considered as being "in world" and you should use this to clean-up the display list and purge dead objects.
- * By default we set the Bounds to be from 0,0 to Game.width,Game.height. I.e. it will match the size given to the game constructor with 0,0 representing the top-left of the display.
- * However 0,0 is actually the center of the world, and if you rotate or scale the world all of that will happen from 0,0.
- * So if you want to make a game in which the world itself will rotate you should adjust the bounds so that 0,0 is the center point, i.e. set them to -1000,-1000,2000,2000 for a 2000x2000 sized world centered around 0,0.
- * @property {Phaser.Rectangle} bounds - Bound of this world that objects can not escape from.
- */
- this.bounds = new Phaser.Rectangle(0, 0, game.width, game.height);
- /**
- * @property {Phaser.Camera} camera - Camera instance.
- */
- this.camera = null;
- };
- Phaser.World.prototype = Object.create(Phaser.Group.prototype);
- Phaser.World.prototype.constructor = Phaser.World;
- /**
- * Initialises the game world.
- *
- * @method Phaser.World#boot
- * @protected
- */
- Phaser.World.prototype.boot = function () {
- this.camera = new Phaser.Camera(this.game, 0, 0, 0, this.game.width, this.game.height);
- this.camera.displayObject = this;
- this.camera.scale = this.scale;
- this.game.camera = this.camera;
- this.game.stage.addChild(this);
- };
- /**
- * Updates the size of this world. Note that this doesn't modify the world x/y coordinates, just the width and height.
- *
- * @method Phaser.World#setBounds
- * @param {number} x - Top left most corner of the world.
- * @param {number} y - Top left most corner of the world.
- * @param {number} width - New width of the world. Can never be smaller than the Game.width.
- * @param {number} height - New height of the world. Can never be smaller than the Game.height.
- */
- Phaser.World.prototype.setBounds = function (x, y, width, height) {
- if (width < this.game.width)
- {
- width = this.game.width;
- }
- if (height < this.game.height)
- {
- height = this.game.height;
- }
- this.bounds.setTo(x, y, width, height);
- if (this.camera.bounds)
- {
- // The Camera can never be smaller than the game size
- this.camera.bounds.setTo(x, y, width, height);
- }
- this.game.physics.setBoundsToWorld();
- };
- /**
- * Destroyer of worlds.
- *
- * @method Phaser.World#shutdown
- */
- Phaser.World.prototype.shutdown = function () {
- // World is a Group, so run a soft destruction on this and all children.
- this.destroy(true, true);
- };
- /**
- * @name Phaser.World#width
- * @property {number} width - Gets or sets the current width of the game world.
- */
- Object.defineProperty(Phaser.World.prototype, "width", {
- get: function () {
- return this.bounds.width;
- },
- set: function (value) {
- this.bounds.width = value;
- }
- });
- /**
- * @name Phaser.World#height
- * @property {number} height - Gets or sets the current height of the game world.
- */
- Object.defineProperty(Phaser.World.prototype, "height", {
- get: function () {
- return this.bounds.height;
- },
- set: function (value) {
- this.bounds.height = value;
- }
- });
- /**
- * @name Phaser.World#centerX
- * @property {number} centerX - Gets the X position corresponding to the center point of the world.
- * @readonly
- */
- Object.defineProperty(Phaser.World.prototype, "centerX", {
- get: function () {
- return this.bounds.halfWidth;
- }
- });
- /**
- * @name Phaser.World#centerY
- * @property {number} centerY - Gets the Y position corresponding to the center point of the world.
- * @readonly
- */
- Object.defineProperty(Phaser.World.prototype, "centerY", {
- get: function () {
- return this.bounds.halfHeight;
- }
- });
- /**
- * @name Phaser.World#randomX
- * @property {number} randomX - Gets a random integer which is lesser than or equal to the current width of the game world.
- * @readonly
- */
- Object.defineProperty(Phaser.World.prototype, "randomX", {
- get: function () {
- if (this.bounds.x < 0)
- {
- return this.game.rnd.integerInRange(this.bounds.x, (this.bounds.width - Math.abs(this.bounds.x)));
- }
- else
- {
- return this.game.rnd.integerInRange(this.bounds.x, this.bounds.width);
- }
- }
- });
- /**
- * @name Phaser.World#randomY
- * @property {number} randomY - Gets a random integer which is lesser than or equal to the current height of the game world.
- * @readonly
- */
- Object.defineProperty(Phaser.World.prototype, "randomY", {
- get: function () {
- if (this.bounds.y < 0)
- {
- return this.game.rnd.integerInRange(this.bounds.y, (this.bounds.height - Math.abs(this.bounds.y)));
- }
- else
- {
- return this.game.rnd.integerInRange(this.bounds.y, this.bounds.height);
- }
- }
- });
- /**
- * @author Richard Davey <rich@photonstorm.com>
- * @copyright 2014 Photon Storm Ltd.
- * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
- */
- /**
- * The ScaleManager object is responsible for helping you manage the scaling, resizing and alignment of your game within the browser.
- *
- * @class Phaser.ScaleManager
- * @constructor
- * @param {Phaser.Game} game - A reference to the currently running game.
- * @param {number} width - The native width of the game.
- * @param {number} height - The native height of the game.
- */
- Phaser.ScaleManager = function (game, width, height) {
- /**
- * @property {Phaser.Game} game - A reference to the currently running game.
- */
- this.game = game;
- /**
- * @property {number} width - Width of the stage after calculation.
- */
- this.width = width;
- /**
- * @property {number} height - Height of the stage after calculation.
- */
- this.height = height;
- /**
- * @property {number} minWidth - Minimum width the canvas should be scaled to (in pixels).
- */
- this.minWidth = null;
- /**
- * @property {number} maxWidth - Maximum width the canvas should be scaled to (in pixels). If null it will scale to whatever width the browser can handle.
- */
- this.maxWidth = null;
- /**
- * @property {number} minHeight - Minimum height the canvas should be scaled to (in pixels).
- */
- this.minHeight = null;
- /**
- * @property {number} maxHeight - Maximum height the canvas should be scaled to (in pixels). If null it will scale to whatever height the browser can handle.
- */
- this.maxHeight = null;
- /**
- * @property {boolean} forceLandscape - If the game should be forced to use Landscape mode, this is set to true by Game.Stage
- * @default
- */
- this.forceLandscape = false;
- /**
- * @property {boolean} forcePortrait - If the game should be forced to use Portrait mode, this is set to true by Game.Stage
- * @default
- */
- this.forcePortrait = false;
- /**
- * @property {boolean} incorrectOrientation - If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true.
- * @default
- */
- this.incorrectOrientation = false;
- /**
- * @property {boolean} pageAlignHorizontally - If you wish to align your game in the middle of the page then you can set this value to true.
- * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing.
- * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
- * @default
- */
- this.pageAlignHorizontally = false;
- /**
- * @property {boolean} pageAlignVertically - If you wish to align your game in the middle of the page then you can set this value to true.
- * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing.
- * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
- * @default
- */
- this.pageAlignVertically = false;
- /**
- * @property {number} maxIterations - The maximum number of times it will try to resize the canvas to fill the browser.
- * @default
- */
- this.maxIterations = 5;
- /**
- * @property {PIXI.Sprite} orientationSprite - The Sprite that is optionally displayed if the browser enters an unsupported orientation.
- */
- this.orientationSprite = null;
- /**
- * @property {Phaser.Signal} enterLandscape - The event that is dispatched when the browser enters landscape orientation.
- */
- this.enterLandscape = new Phaser.Signal();
- /**
- * @property {Phaser.Signal} enterPortrait - The event that is dispatched when the browser enters horizontal orientation.
- */
- this.enterPortrait = new Phaser.Signal();
- /**
- * @property {Phaser.Signal} enterIncorrectOrientation - The event that is dispatched when the browser enters an incorrect orientation, as defined by forceOrientation.
- */
- this.enterIncorrectOrientation = new Phaser.Signal();
- /**
- * @property {Phaser.Signal} leaveIncorrectOrientation - The event that is dispatched when the browser leaves an incorrect orientation, as defined by forceOrientation.
- */
- this.leaveIncorrectOrientation = new Phaser.Signal();
- /**
- * @property {Phaser.Signal} hasResized - The event that is dispatched when the game scale changes.
- */
- this.hasResized = new Phaser.Signal();
- /**
- * This is the DOM element that will have the Full Screen mode called on it. It defaults to the game canvas, but can be retargetted to any valid DOM element.
- * If you adjust this property it's up to you to see it has the correct CSS applied, and that you have contained the game canvas correctly.
- * Note that if you use a scale property of EXACT_FIT then fullScreenTarget will have its width and height style set to 100%.
- * @property {any} fullScreenTarget
- */
- this.fullScreenTarget = this.game.canvas;
- /**
- * @property {Phaser.Signal} enterFullScreen - The event that is dispatched when the browser enters full screen mode (if it supports the FullScreen API).
- */
- this.enterFullScreen = new Phaser.Signal();
- /**
- * @property {Phaser.Signal} leaveFullScreen - The event that is dispatched when the browser leaves full screen mode (if it supports the FullScreen API).
- */
- this.leaveFullScreen = new Phaser.Signal();
- /**
- * @property {number} orientation - The orientation value of the game (as defined by window.orientation if set). 90 = landscape. 0 = portrait.
- */
- this.orienta