PageRenderTime 251ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 2ms

/build/custom/phaser-arcade-physics.js

https://gitlab.com/lobsterhands/phaser
JavaScript | 17639 lines | 8119 code | 3354 blank | 6166 comment | 1201 complexity | 3d0643572fac43e8b7e174e36a9f2ebf MD5 | raw file
  1. /**
  2. * @author Richard Davey <rich@photonstorm.com>
  3. * @copyright 2014 Photon Storm Ltd.
  4. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  5. *
  6. * @overview
  7. *
  8. * Phaser - http://phaser.io
  9. *
  10. * v2.0.3 "Allorallen" - Built: Fri Apr 11 2014 13:08:30
  11. *
  12. * By Richard Davey http://www.photonstorm.com @photonstorm
  13. *
  14. * Phaser is a fun, free and fast 2D game framework for making HTML5 games
  15. * for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
  16. *
  17. * Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
  18. * Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
  19. * Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
  20. *
  21. * Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser
  22. * and my love of framework development originate.
  23. *
  24. * Follow development at http://phaser.io and on our forum
  25. *
  26. * "If you want your children to be intelligent, read them fairy tales."
  27. * "If you want them to be more intelligent, read them more fairy tales."
  28. * -- Albert Einstein
  29. */
  30. /**
  31. * @author Mat Groves http://matgroves.com/ @Doormat23
  32. */
  33. (function(){
  34. var root = this;
  35. /**
  36. * @author Mat Groves http://matgroves.com/ @Doormat23
  37. */
  38. /**
  39. * @module PIXI
  40. */
  41. var PIXI = PIXI || {};
  42. /*
  43. *
  44. * This file contains a lot of pixi consts which are used across the rendering engine
  45. * @class Consts
  46. */
  47. PIXI.WEBGL_RENDERER = 0;
  48. PIXI.CANVAS_RENDERER = 1;
  49. // useful for testing against if your lib is using pixi.
  50. PIXI.VERSION = "v1.5.2";
  51. // the various blend modes supported by pixi
  52. PIXI.blendModes = {
  53. NORMAL:0,
  54. ADD:1,
  55. MULTIPLY:2,
  56. SCREEN:3,
  57. OVERLAY:4,
  58. DARKEN:5,
  59. LIGHTEN:6,
  60. COLOR_DODGE:7,
  61. COLOR_BURN:8,
  62. HARD_LIGHT:9,
  63. SOFT_LIGHT:10,
  64. DIFFERENCE:11,
  65. EXCLUSION:12,
  66. HUE:13,
  67. SATURATION:14,
  68. COLOR:15,
  69. LUMINOSITY:16
  70. };
  71. // the scale modes
  72. PIXI.scaleModes = {
  73. DEFAULT:0,
  74. LINEAR:0,
  75. NEAREST:1
  76. };
  77. // interaction frequency
  78. PIXI.INTERACTION_FREQUENCY = 30;
  79. PIXI.AUTO_PREVENT_DEFAULT = true;
  80. PIXI.RAD_TO_DEG = 180 / Math.PI;
  81. PIXI.DEG_TO_RAD = Math.PI / 180;
  82. /**
  83. * @author Mat Groves http://matgroves.com/ @Doormat23
  84. */
  85. /**
  86. * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis.
  87. *
  88. * @class Point
  89. * @constructor
  90. * @param x {Number} position of the point on the x axis
  91. * @param y {Number} position of the point on the y axis
  92. */
  93. PIXI.Point = function(x, y)
  94. {
  95. /**
  96. * @property x
  97. * @type Number
  98. * @default 0
  99. */
  100. this.x = x || 0;
  101. /**
  102. * @property y
  103. * @type Number
  104. * @default 0
  105. */
  106. this.y = y || 0;
  107. };
  108. /**
  109. * Creates a clone of this point
  110. *
  111. * @method clone
  112. * @return {Point} a copy of the point
  113. */
  114. PIXI.Point.prototype.clone = function()
  115. {
  116. return new PIXI.Point(this.x, this.y);
  117. };
  118. // constructor
  119. PIXI.Point.prototype.constructor = PIXI.Point;
  120. PIXI.Point.prototype.set = function(x, y)
  121. {
  122. this.x = x || 0;
  123. this.y = y || ( (y !== 0) ? this.x : 0 ) ;
  124. };
  125. /**
  126. * @author Mat Groves http://matgroves.com/
  127. */
  128. /**
  129. * 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.
  130. *
  131. * @class Rectangle
  132. * @constructor
  133. * @param x {Number} The X coord of the upper-left corner of the rectangle
  134. * @param y {Number} The Y coord of the upper-left corner of the rectangle
  135. * @param width {Number} The overall width of this rectangle
  136. * @param height {Number} The overall height of this rectangle
  137. */
  138. PIXI.Rectangle = function(x, y, width, height)
  139. {
  140. /**
  141. * @property x
  142. * @type Number
  143. * @default 0
  144. */
  145. this.x = x || 0;
  146. /**
  147. * @property y
  148. * @type Number
  149. * @default 0
  150. */
  151. this.y = y || 0;
  152. /**
  153. * @property width
  154. * @type Number
  155. * @default 0
  156. */
  157. this.width = width || 0;
  158. /**
  159. * @property height
  160. * @type Number
  161. * @default 0
  162. */
  163. this.height = height || 0;
  164. };
  165. /**
  166. * Creates a clone of this Rectangle
  167. *
  168. * @method clone
  169. * @return {Rectangle} a copy of the rectangle
  170. */
  171. PIXI.Rectangle.prototype.clone = function()
  172. {
  173. return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
  174. };
  175. /**
  176. * Checks whether the x and y coordinates passed to this function are contained within this Rectangle
  177. *
  178. * @method contains
  179. * @param x {Number} The X coordinate of the point to test
  180. * @param y {Number} The Y coordinate of the point to test
  181. * @return {Boolean} Whether the x/y coords are within this Rectangle
  182. */
  183. PIXI.Rectangle.prototype.contains = function(x, y)
  184. {
  185. if(this.width <= 0 || this.height <= 0)
  186. return false;
  187. var x1 = this.x;
  188. if(x >= x1 && x <= x1 + this.width)
  189. {
  190. var y1 = this.y;
  191. if(y >= y1 && y <= y1 + this.height)
  192. {
  193. return true;
  194. }
  195. }
  196. return false;
  197. };
  198. // constructor
  199. PIXI.Rectangle.prototype.constructor = PIXI.Rectangle;
  200. PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0);
  201. /**
  202. * @author Adrien Brault <adrien.brault@gmail.com>
  203. */
  204. /**
  205. * @class Polygon
  206. * @constructor
  207. * @param points* {Array<Point>|Array<Number>|Point...|Number...} This can be an array of Points that form the polygon,
  208. * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be
  209. * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the
  210. * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are
  211. * Numbers.
  212. */
  213. PIXI.Polygon = function(points)
  214. {
  215. //if points isn't an array, use arguments as the array
  216. if(!(points instanceof Array))
  217. points = Array.prototype.slice.call(arguments);
  218. //if this is a flat array of numbers, convert it to points
  219. if(typeof points[0] === 'number') {
  220. var p = [];
  221. for(var i = 0, il = points.length; i < il; i+=2) {
  222. p.push(
  223. new PIXI.Point(points[i], points[i + 1])
  224. );
  225. }
  226. points = p;
  227. }
  228. this.points = points;
  229. };
  230. /**
  231. * Creates a clone of this polygon
  232. *
  233. * @method clone
  234. * @return {Polygon} a copy of the polygon
  235. */
  236. PIXI.Polygon.prototype.clone = function()
  237. {
  238. var points = [];
  239. for (var i=0; i<this.points.length; i++) {
  240. points.push(this.points[i].clone());
  241. }
  242. return new PIXI.Polygon(points);
  243. };
  244. /**
  245. * Checks whether the x and y coordinates passed to this function are contained within this polygon
  246. *
  247. * @method contains
  248. * @param x {Number} The X coordinate of the point to test
  249. * @param y {Number} The Y coordinate of the point to test
  250. * @return {Boolean} Whether the x/y coordinates are within this polygon
  251. */
  252. PIXI.Polygon.prototype.contains = function(x, y)
  253. {
  254. var inside = false;
  255. // use some raycasting to test hits
  256. // https://github.com/substack/point-in-polygon/blob/master/index.js
  257. for(var i = 0, j = this.points.length - 1; i < this.points.length; j = i++) {
  258. var xi = this.points[i].x, yi = this.points[i].y,
  259. xj = this.points[j].x, yj = this.points[j].y,
  260. intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  261. if(intersect) inside = !inside;
  262. }
  263. return inside;
  264. };
  265. // constructor
  266. PIXI.Polygon.prototype.constructor = PIXI.Polygon;
  267. /**
  268. * @author Chad Engler <chad@pantherdev.com>
  269. */
  270. /**
  271. * The Circle object can be used to specify a hit area for displayObjects
  272. *
  273. * @class Circle
  274. * @constructor
  275. * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this circle
  276. * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this circle
  277. * @param radius {Number} The radius of the circle
  278. */
  279. PIXI.Circle = function(x, y, radius)
  280. {
  281. /**
  282. * @property x
  283. * @type Number
  284. * @default 0
  285. */
  286. this.x = x || 0;
  287. /**
  288. * @property y
  289. * @type Number
  290. * @default 0
  291. */
  292. this.y = y || 0;
  293. /**
  294. * @property radius
  295. * @type Number
  296. * @default 0
  297. */
  298. this.radius = radius || 0;
  299. };
  300. /**
  301. * Creates a clone of this Circle instance
  302. *
  303. * @method clone
  304. * @return {Circle} a copy of the polygon
  305. */
  306. PIXI.Circle.prototype.clone = function()
  307. {
  308. return new PIXI.Circle(this.x, this.y, this.radius);
  309. };
  310. /**
  311. * Checks whether the x, and y coordinates passed to this function are contained within this circle
  312. *
  313. * @method contains
  314. * @param x {Number} The X coordinate of the point to test
  315. * @param y {Number} The Y coordinate of the point to test
  316. * @return {Boolean} Whether the x/y coordinates are within this polygon
  317. */
  318. PIXI.Circle.prototype.contains = function(x, y)
  319. {
  320. if(this.radius <= 0)
  321. return false;
  322. var dx = (this.x - x),
  323. dy = (this.y - y),
  324. r2 = this.radius * this.radius;
  325. dx *= dx;
  326. dy *= dy;
  327. return (dx + dy <= r2);
  328. };
  329. // constructor
  330. PIXI.Circle.prototype.constructor = PIXI.Circle;
  331. /**
  332. * @author Chad Engler <chad@pantherdev.com>
  333. */
  334. /**
  335. * The Ellipse object can be used to specify a hit area for displayObjects
  336. *
  337. * @class Ellipse
  338. * @constructor
  339. * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this ellipse
  340. * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this ellipse
  341. * @param width {Number} The overall width of this ellipse
  342. * @param height {Number} The overall height of this ellipse
  343. */
  344. PIXI.Ellipse = function(x, y, width, height)
  345. {
  346. /**
  347. * @property x
  348. * @type Number
  349. * @default 0
  350. */
  351. this.x = x || 0;
  352. /**
  353. * @property y
  354. * @type Number
  355. * @default 0
  356. */
  357. this.y = y || 0;
  358. /**
  359. * @property width
  360. * @type Number
  361. * @default 0
  362. */
  363. this.width = width || 0;
  364. /**
  365. * @property height
  366. * @type Number
  367. * @default 0
  368. */
  369. this.height = height || 0;
  370. };
  371. /**
  372. * Creates a clone of this Ellipse instance
  373. *
  374. * @method clone
  375. * @return {Ellipse} a copy of the ellipse
  376. */
  377. PIXI.Ellipse.prototype.clone = function()
  378. {
  379. return new PIXI.Ellipse(this.x, this.y, this.width, this.height);
  380. };
  381. /**
  382. * Checks whether the x and y coordinates passed to this function are contained within this ellipse
  383. *
  384. * @method contains
  385. * @param x {Number} The X coordinate of the point to test
  386. * @param y {Number} The Y coordinate of the point to test
  387. * @return {Boolean} Whether the x/y coords are within this ellipse
  388. */
  389. PIXI.Ellipse.prototype.contains = function(x, y)
  390. {
  391. if(this.width <= 0 || this.height <= 0)
  392. return false;
  393. //normalize the coords to an ellipse with center 0,0
  394. var normx = ((x - this.x) / this.width),
  395. normy = ((y - this.y) / this.height);
  396. normx *= normx;
  397. normy *= normy;
  398. return (normx + normy <= 1);
  399. };
  400. /**
  401. * Returns the framing rectangle of the ellipse as a PIXI.Rectangle object
  402. *
  403. * @method getBounds
  404. * @return {Rectangle} the framing rectangle
  405. */
  406. PIXI.Ellipse.prototype.getBounds = function()
  407. {
  408. return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
  409. };
  410. // constructor
  411. PIXI.Ellipse.prototype.constructor = PIXI.Ellipse;
  412. /**
  413. * @author Mat Groves http://matgroves.com/ @Doormat23
  414. */
  415. PIXI.determineMatrixArrayType = function() {
  416. return (typeof Float32Array !== 'undefined') ? Float32Array : Array;
  417. };
  418. /*
  419. * @class Matrix2
  420. * The Matrix2 class will choose the best type of array to use between
  421. * a regular javascript Array and a Float32Array if the latter is available
  422. *
  423. */
  424. PIXI.Matrix2 = PIXI.determineMatrixArrayType();
  425. /*
  426. * @class Matrix
  427. * The Matrix class is now an object, which makes it a lot faster,
  428. * here is a representation of it :
  429. * | a | b | tx|
  430. * | c | c | ty|
  431. * | 0 | 0 | 1 |
  432. *
  433. */
  434. PIXI.Matrix = function()
  435. {
  436. this.a = 1;
  437. this.b = 0;
  438. this.c = 0;
  439. this.d = 1;
  440. this.tx = 0;
  441. this.ty = 0;
  442. };
  443. /**
  444. * Creates a pixi matrix object based on the array given as a parameter
  445. *
  446. * @method fromArray
  447. * @param array {Array} The array that the matrix will be filled with
  448. */
  449. PIXI.Matrix.prototype.fromArray = function(array)
  450. {
  451. this.a = array[0];
  452. this.b = array[1];
  453. this.c = array[3];
  454. this.d = array[4];
  455. this.tx = array[2];
  456. this.ty = array[5];
  457. };
  458. /**
  459. * Creates an array from the current Matrix object
  460. *
  461. * @method toArray
  462. * @param transpose {Boolean} Whether we need to transpose the matrix or not
  463. * @return array {Array} the newly created array which contains the matrix
  464. */
  465. PIXI.Matrix.prototype.toArray = function(transpose)
  466. {
  467. if(!this.array) this.array = new Float32Array(9);
  468. var array = this.array;
  469. if(transpose)
  470. {
  471. this.array[0] = this.a;
  472. this.array[1] = this.c;
  473. this.array[2] = 0;
  474. this.array[3] = this.b;
  475. this.array[4] = this.d;
  476. this.array[5] = 0;
  477. this.array[6] = this.tx;
  478. this.array[7] = this.ty;
  479. this.array[8] = 1;
  480. }
  481. else
  482. {
  483. this.array[0] = this.a;
  484. this.array[1] = this.b;
  485. this.array[2] = this.tx;
  486. this.array[3] = this.c;
  487. this.array[4] = this.d;
  488. this.array[5] = this.ty;
  489. this.array[6] = 0;
  490. this.array[7] = 0;
  491. this.array[8] = 1;
  492. }
  493. return array;//[this.a, this.b, this.tx, this.c, this.d, this.ty, 0, 0, 1];
  494. };
  495. PIXI.identityMatrix = new PIXI.Matrix();
  496. /**
  497. * @author Mat Groves http://matgroves.com/ @Doormat23
  498. */
  499. /**
  500. * The base class for all objects that are rendered on the screen.
  501. *
  502. * @class DisplayObject
  503. * @constructor
  504. */
  505. PIXI.DisplayObject = function()
  506. {
  507. /**
  508. * The coordinate of the object relative to the local coordinates of the parent.
  509. *
  510. * @property position
  511. * @type Point
  512. */
  513. this.position = new PIXI.Point();
  514. /**
  515. * The scale factor of the object.
  516. *
  517. * @property scale
  518. * @type Point
  519. */
  520. this.scale = new PIXI.Point(1,1);//{x:1, y:1};
  521. /**
  522. * The pivot point of the displayObject that it rotates around
  523. *
  524. * @property pivot
  525. * @type Point
  526. */
  527. this.pivot = new PIXI.Point(0,0);
  528. /**
  529. * The rotation of the object in radians.
  530. *
  531. * @property rotation
  532. * @type Number
  533. */
  534. this.rotation = 0;
  535. /**
  536. * The opacity of the object.
  537. *
  538. * @property alpha
  539. * @type Number
  540. */
  541. this.alpha = 1;
  542. /**
  543. * The visibility of the object.
  544. *
  545. * @property visible
  546. * @type Boolean
  547. */
  548. this.visible = true;
  549. /**
  550. * This is the defined area that will pick up mouse / touch events. It is null by default.
  551. * 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)
  552. *
  553. * @property hitArea
  554. * @type Rectangle|Circle|Ellipse|Polygon
  555. */
  556. this.hitArea = null;
  557. /**
  558. * This is used to indicate if the displayObject should display a mouse hand cursor on rollover
  559. *
  560. * @property buttonMode
  561. * @type Boolean
  562. */
  563. this.buttonMode = false;
  564. /**
  565. * Can this object be rendered
  566. *
  567. * @property renderable
  568. * @type Boolean
  569. */
  570. this.renderable = false;
  571. /**
  572. * [read-only] The display object container that contains this display object.
  573. *
  574. * @property parent
  575. * @type DisplayObjectContainer
  576. * @readOnly
  577. */
  578. this.parent = null;
  579. /**
  580. * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage.
  581. *
  582. * @property stage
  583. * @type Stage
  584. * @readOnly
  585. */
  586. this.stage = null;
  587. /**
  588. * [read-only] The multiplied alpha of the displayObject
  589. *
  590. * @property worldAlpha
  591. * @type Number
  592. * @readOnly
  593. */
  594. this.worldAlpha = 1;
  595. /**
  596. * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property
  597. *
  598. * @property _interactive
  599. * @type Boolean
  600. * @readOnly
  601. * @private
  602. */
  603. this._interactive = false;
  604. /**
  605. * 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
  606. *
  607. * @property defaultCursor
  608. * @type String
  609. *
  610. */
  611. this.defaultCursor = 'pointer';
  612. /**
  613. * [read-only] Current transform of the object based on world (parent) factors
  614. *
  615. * @property worldTransform
  616. * @type Mat3
  617. * @readOnly
  618. * @private
  619. */
  620. this.worldTransform = new PIXI.Matrix();
  621. /**
  622. * [NYI] Unknown
  623. *
  624. * @property color
  625. * @type Array<>
  626. * @private
  627. */
  628. this.color = [];
  629. /**
  630. * [NYI] Holds whether or not this object is dynamic, for rendering optimization
  631. *
  632. * @property dynamic
  633. * @type Boolean
  634. * @private
  635. */
  636. this.dynamic = true;
  637. // cached sin rotation and cos rotation
  638. this._sr = 0;
  639. this._cr = 1;
  640. /**
  641. * The area the filter is applied to like the hitArea this is used as more of an optimisation
  642. * rather than figuring out the dimensions of the displayObject each frame you can set this rectangle
  643. *
  644. * @property filterArea
  645. * @type Rectangle
  646. */
  647. this.filterArea = null;//new PIXI.Rectangle(0,0,1,1);
  648. /**
  649. * The original, cached bounds of the object
  650. *
  651. * @property _bounds
  652. * @type Rectangle
  653. * @private
  654. */
  655. this._bounds = new PIXI.Rectangle(0, 0, 1, 1);
  656. /**
  657. * The most up-to-date bounds of the object
  658. *
  659. * @property _currentBounds
  660. * @type Rectangle
  661. * @private
  662. */
  663. this._currentBounds = null;
  664. /**
  665. * The original, cached mask of the object
  666. *
  667. * @property _currentBounds
  668. * @type Rectangle
  669. * @private
  670. */
  671. this._mask = null;
  672. this._cacheAsBitmap = false;
  673. this._cacheIsDirty = false;
  674. /*
  675. * MOUSE Callbacks
  676. */
  677. /**
  678. * A callback that is used when the users clicks on the displayObject with their mouse
  679. * @method click
  680. * @param interactionData {InteractionData}
  681. */
  682. /**
  683. * A callback that is used when the user clicks the mouse down over the sprite
  684. * @method mousedown
  685. * @param interactionData {InteractionData}
  686. */
  687. /**
  688. * A callback that is used when the user releases the mouse that was over the displayObject
  689. * for this callback to be fired the mouse must have been pressed down over the displayObject
  690. * @method mouseup
  691. * @param interactionData {InteractionData}
  692. */
  693. /**
  694. * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject
  695. * for this callback to be fired, The touch must have started over the displayObject
  696. * @method mouseupoutside
  697. * @param interactionData {InteractionData}
  698. */
  699. /**
  700. * A callback that is used when the users mouse rolls over the displayObject
  701. * @method mouseover
  702. * @param interactionData {InteractionData}
  703. */
  704. /**
  705. * A callback that is used when the users mouse leaves the displayObject
  706. * @method mouseout
  707. * @param interactionData {InteractionData}
  708. */
  709. /*
  710. * TOUCH Callbacks
  711. */
  712. /**
  713. * A callback that is used when the users taps on the sprite with their finger
  714. * basically a touch version of click
  715. * @method tap
  716. * @param interactionData {InteractionData}
  717. */
  718. /**
  719. * A callback that is used when the user touches over the displayObject
  720. * @method touchstart
  721. * @param interactionData {InteractionData}
  722. */
  723. /**
  724. * A callback that is used when the user releases a touch over the displayObject
  725. * @method touchend
  726. * @param interactionData {InteractionData}
  727. */
  728. /**
  729. * A callback that is used when the user releases the touch that was over the displayObject
  730. * for this callback to be fired, The touch must have started over the sprite
  731. * @method touchendoutside
  732. * @param interactionData {InteractionData}
  733. */
  734. };
  735. // constructor
  736. PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject;
  737. /**
  738. * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default
  739. * Instead of using this function you can now simply set the interactive property to true or false
  740. *
  741. * @method setInteractive
  742. * @param interactive {Boolean}
  743. * @deprecated Simply set the `interactive` property directly
  744. */
  745. PIXI.DisplayObject.prototype.setInteractive = function(interactive)
  746. {
  747. this.interactive = interactive;
  748. };
  749. /**
  750. * Indicates if the sprite will have touch and mouse interactivity. It is false by default
  751. *
  752. * @property interactive
  753. * @type Boolean
  754. * @default false
  755. */
  756. Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', {
  757. get: function() {
  758. return this._interactive;
  759. },
  760. set: function(value) {
  761. this._interactive = value;
  762. // TODO more to be done here..
  763. // need to sort out a re-crawl!
  764. if(this.stage)this.stage.dirty = true;
  765. }
  766. });
  767. /**
  768. * [read-only] Indicates if the sprite is globaly visible.
  769. *
  770. * @property worldVisible
  771. * @type Boolean
  772. */
  773. Object.defineProperty(PIXI.DisplayObject.prototype, 'worldVisible', {
  774. get: function() {
  775. var item = this;
  776. do
  777. {
  778. if(!item.visible)return false;
  779. item = item.parent;
  780. }
  781. while(item);
  782. return true;
  783. }
  784. });
  785. /**
  786. * 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.
  787. * In PIXI a regular mask must be a PIXI.Graphics object. This allows for much faster masking in canvas as it utilises shape clipping.
  788. * To remove a mask, set this property to null.
  789. *
  790. * @property mask
  791. * @type Graphics
  792. */
  793. Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', {
  794. get: function() {
  795. return this._mask;
  796. },
  797. set: function(value) {
  798. if(this._mask)this._mask.isMask = false;
  799. this._mask = value;
  800. if(this._mask)this._mask.isMask = true;
  801. }
  802. });
  803. /**
  804. * Sets the filters for the displayObject.
  805. * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer.
  806. * To remove filters simply set this property to 'null'
  807. * @property filters
  808. * @type Array An array of filters
  809. */
  810. Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', {
  811. get: function() {
  812. return this._filters;
  813. },
  814. set: function(value) {
  815. if(value)
  816. {
  817. // now put all the passes in one place..
  818. var passes = [];
  819. for (var i = 0; i < value.length; i++)
  820. {
  821. var filterPasses = value[i].passes;
  822. for (var j = 0; j < filterPasses.length; j++)
  823. {
  824. passes.push(filterPasses[j]);
  825. }
  826. }
  827. // TODO change this as it is legacy
  828. this._filterBlock = {target:this, filterPasses:passes};
  829. }
  830. this._filters = value;
  831. }
  832. });
  833. /**
  834. * Set weather or not a the display objects is cached as a bitmap.
  835. * 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
  836. * To remove filters simply set this property to 'null'
  837. * @property cacheAsBitmap
  838. * @type Boolean
  839. */
  840. Object.defineProperty(PIXI.DisplayObject.prototype, 'cacheAsBitmap', {
  841. get: function() {
  842. return this._cacheAsBitmap;
  843. },
  844. set: function(value) {
  845. if(this._cacheAsBitmap === value)return;
  846. if(value)
  847. {
  848. //this._cacheIsDirty = true;
  849. this._generateCachedSprite();
  850. }
  851. else
  852. {
  853. this._destroyCachedSprite();
  854. }
  855. this._cacheAsBitmap = value;
  856. }
  857. });
  858. /*
  859. * Updates the object transform for rendering
  860. *
  861. * @method updateTransform
  862. * @private
  863. */
  864. PIXI.DisplayObject.prototype.updateTransform = function()
  865. {
  866. // TODO OPTIMIZE THIS!! with dirty
  867. if(this.rotation !== this.rotationCache)
  868. {
  869. this.rotationCache = this.rotation;
  870. this._sr = Math.sin(this.rotation);
  871. this._cr = Math.cos(this.rotation);
  872. }
  873. // var localTransform = this.localTransform//.toArray();
  874. var parentTransform = this.parent.worldTransform;//.toArray();
  875. var worldTransform = this.worldTransform;//.toArray();
  876. var px = this.pivot.x;
  877. var py = this.pivot.y;
  878. var a00 = this._cr * this.scale.x,
  879. a01 = -this._sr * this.scale.y,
  880. a10 = this._sr * this.scale.x,
  881. a11 = this._cr * this.scale.y,
  882. a02 = this.position.x - a00 * px - py * a01,
  883. a12 = this.position.y - a11 * py - px * a10,
  884. b00 = parentTransform.a, b01 = parentTransform.b,
  885. b10 = parentTransform.c, b11 = parentTransform.d;
  886. worldTransform.a = b00 * a00 + b01 * a10;
  887. worldTransform.b = b00 * a01 + b01 * a11;
  888. worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx;
  889. worldTransform.c = b10 * a00 + b11 * a10;
  890. worldTransform.d = b10 * a01 + b11 * a11;
  891. worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty;
  892. this.worldAlpha = this.alpha * this.parent.worldAlpha;
  893. };
  894. /**
  895. * Retrieves the bounds of the displayObject as a rectangle object
  896. *
  897. * @method getBounds
  898. * @return {Rectangle} the rectangular bounding area
  899. */
  900. PIXI.DisplayObject.prototype.getBounds = function( matrix )
  901. {
  902. matrix = matrix;//just to get passed js hinting (and preserve inheritance)
  903. return PIXI.EmptyRectangle;
  904. };
  905. /**
  906. * Retrieves the local bounds of the displayObject as a rectangle object
  907. *
  908. * @method getLocalBounds
  909. * @return {Rectangle} the rectangular bounding area
  910. */
  911. PIXI.DisplayObject.prototype.getLocalBounds = function()
  912. {
  913. return this.getBounds(PIXI.identityMatrix);///PIXI.EmptyRectangle();
  914. };
  915. /**
  916. * Sets the object's stage reference, the stage this object is connected to
  917. *
  918. * @method setStageReference
  919. * @param stage {Stage} the stage that the object will have as its current stage reference
  920. */
  921. PIXI.DisplayObject.prototype.setStageReference = function(stage)
  922. {
  923. this.stage = stage;
  924. if(this._interactive)this.stage.dirty = true;
  925. };
  926. PIXI.DisplayObject.prototype.generateTexture = function(renderer)
  927. {
  928. var bounds = this.getLocalBounds();
  929. var renderTexture = new PIXI.RenderTexture(bounds.width | 0, bounds.height | 0, renderer);
  930. renderTexture.render(this);
  931. return renderTexture;
  932. };
  933. PIXI.DisplayObject.prototype.updateCache = function()
  934. {
  935. this._generateCachedSprite();
  936. };
  937. PIXI.DisplayObject.prototype._renderCachedSprite = function(renderSession)
  938. {
  939. if(renderSession.gl)
  940. {
  941. PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession);
  942. }
  943. else
  944. {
  945. PIXI.Sprite.prototype._renderCanvas.call(this._cachedSprite, renderSession);
  946. }
  947. };
  948. PIXI.DisplayObject.prototype._generateCachedSprite = function()//renderSession)
  949. {
  950. this._cacheAsBitmap = false;
  951. var bounds = this.getLocalBounds();
  952. if(!this._cachedSprite)
  953. {
  954. var renderTexture = new PIXI.RenderTexture(bounds.width | 0, bounds.height | 0);//, renderSession.renderer);
  955. this._cachedSprite = new PIXI.Sprite(renderTexture);
  956. this._cachedSprite.worldTransform = this.worldTransform;
  957. }
  958. else
  959. {
  960. this._cachedSprite.texture.resize(bounds.width | 0, bounds.height | 0);
  961. }
  962. //REMOVE filter!
  963. var tempFilters = this._filters;
  964. this._filters = null;
  965. this._cachedSprite.filters = tempFilters;
  966. this._cachedSprite.texture.render(this);
  967. this._filters = tempFilters;
  968. this._cacheAsBitmap = true;
  969. };
  970. /**
  971. * Renders the object using the WebGL renderer
  972. *
  973. * @method _renderWebGL
  974. * @param renderSession {RenderSession}
  975. * @private
  976. */
  977. PIXI.DisplayObject.prototype._destroyCachedSprite = function()
  978. {
  979. if(!this._cachedSprite)return;
  980. this._cachedSprite.texture.destroy(true);
  981. // console.log("DESTROY")
  982. // let the gc collect the unused sprite
  983. // TODO could be object pooled!
  984. this._cachedSprite = null;
  985. };
  986. PIXI.DisplayObject.prototype._renderWebGL = function(renderSession)
  987. {
  988. // OVERWRITE;
  989. // this line is just here to pass jshinting :)
  990. renderSession = renderSession;
  991. };
  992. /**
  993. * Renders the object using the Canvas renderer
  994. *
  995. * @method _renderCanvas
  996. * @param renderSession {RenderSession}
  997. * @private
  998. */
  999. PIXI.DisplayObject.prototype._renderCanvas = function(renderSession)
  1000. {
  1001. // OVERWRITE;
  1002. // this line is just here to pass jshinting :)
  1003. renderSession = renderSession;
  1004. };
  1005. /**
  1006. * The position of the displayObject on the x axis relative to the local coordinates of the parent.
  1007. *
  1008. * @property x
  1009. * @type Number
  1010. */
  1011. Object.defineProperty(PIXI.DisplayObject.prototype, 'x', {
  1012. get: function() {
  1013. return this.position.x;
  1014. },
  1015. set: function(value) {
  1016. this.position.x = value;
  1017. }
  1018. });
  1019. /**
  1020. * The position of the displayObject on the y axis relative to the local coordinates of the parent.
  1021. *
  1022. * @property y
  1023. * @type Number
  1024. */
  1025. Object.defineProperty(PIXI.DisplayObject.prototype, 'y', {
  1026. get: function() {
  1027. return this.position.y;
  1028. },
  1029. set: function(value) {
  1030. this.position.y = value;
  1031. }
  1032. });
  1033. /**
  1034. * @author Mat Groves http://matgroves.com/ @Doormat23
  1035. */
  1036. /**
  1037. * A DisplayObjectContainer represents a collection of display objects.
  1038. * It is the base class of all display objects that act as a container for other objects.
  1039. *
  1040. * @class DisplayObjectContainer
  1041. * @extends DisplayObject
  1042. * @constructor
  1043. */
  1044. PIXI.DisplayObjectContainer = function()
  1045. {
  1046. PIXI.DisplayObject.call( this );
  1047. /**
  1048. * [read-only] The array of children of this container.
  1049. *
  1050. * @property children
  1051. * @type Array<DisplayObject>
  1052. * @readOnly
  1053. */
  1054. this.children = [];
  1055. };
  1056. // constructor
  1057. PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype );
  1058. PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer;
  1059. /**
  1060. * The width of the displayObjectContainer, setting this will actually modify the scale to achieve the value set
  1061. *
  1062. * @property width
  1063. * @type Number
  1064. */
  1065. /*
  1066. Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'width', {
  1067. get: function() {
  1068. return this.scale.x * this.getLocalBounds().width;
  1069. },
  1070. set: function(value) {
  1071. this.scale.x = value / (this.getLocalBounds().width/this.scale.x);
  1072. this._width = value;
  1073. }
  1074. });
  1075. */
  1076. /**
  1077. * The height of the displayObjectContainer, setting this will actually modify the scale to achieve the value set
  1078. *
  1079. * @property height
  1080. * @type Number
  1081. */
  1082. /*
  1083. Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'height', {
  1084. get: function() {
  1085. return this.scale.y * this.getLocalBounds().height;
  1086. },
  1087. set: function(value) {
  1088. this.scale.y = value / (this.getLocalBounds().height/this.scale.y);
  1089. this._height = value;
  1090. }
  1091. });
  1092. */
  1093. /**
  1094. * Adds a child to the container.
  1095. *
  1096. * @method addChild
  1097. * @param child {DisplayObject} The DisplayObject to add to the container
  1098. */
  1099. PIXI.DisplayObjectContainer.prototype.addChild = function(child)
  1100. {
  1101. this.addChildAt(child, this.children.length);
  1102. };
  1103. /**
  1104. * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown
  1105. *
  1106. * @method addChildAt
  1107. * @param child {DisplayObject} The child to add
  1108. * @param index {Number} The index to place the child in
  1109. */
  1110. PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index)
  1111. {
  1112. if(index >= 0 && index <= this.children.length)
  1113. {
  1114. if(child.parent)
  1115. {
  1116. child.parent.removeChild(child);
  1117. }
  1118. child.parent = this;
  1119. this.children.splice(index, 0, child);
  1120. if(this.stage)child.setStageReference(this.stage);
  1121. }
  1122. else
  1123. {
  1124. throw new Error(child + ' The index '+ index +' supplied is out of bounds ' + this.children.length);
  1125. }
  1126. };
  1127. /**
  1128. * [NYI] Swaps the depth of 2 displayObjects
  1129. *
  1130. * @method swapChildren
  1131. * @param child {DisplayObject}
  1132. * @param child2 {DisplayObject}
  1133. * @private
  1134. */
  1135. PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2)
  1136. {
  1137. if(child === child2) {
  1138. return;
  1139. }
  1140. var index1 = this.children.indexOf(child);
  1141. var index2 = this.children.indexOf(child2);
  1142. if(index1 < 0 || index2 < 0) {
  1143. throw new Error('swapChildren: Both the supplied DisplayObjects must be a child of the caller.');
  1144. }
  1145. this.children[index1] = child2;
  1146. this.children[index2] = child;
  1147. };
  1148. /**
  1149. * Returns the child at the specified index
  1150. *
  1151. * @method getChildAt
  1152. * @param index {Number} The index to get the child from
  1153. */
  1154. PIXI.DisplayObjectContainer.prototype.getChildAt = function(index)
  1155. {
  1156. if(index >= 0 && index < this.children.length)
  1157. {
  1158. return this.children[index];
  1159. }
  1160. else
  1161. {
  1162. throw new Error('Supplied index does not exist in the child list, or the supplied DisplayObject must be a child of the caller');
  1163. }
  1164. };
  1165. /**
  1166. * Removes a child from the container.
  1167. *
  1168. * @method removeChild
  1169. * @param child {DisplayObject} The DisplayObject to remove
  1170. */
  1171. PIXI.DisplayObjectContainer.prototype.removeChild = function(child)
  1172. {
  1173. return this.removeChildAt( this.children.indexOf( child ) );
  1174. };
  1175. /**
  1176. * Removes a child from the specified index position in the child list of the container.
  1177. *
  1178. * @method removeChildAt
  1179. * @param index {Number} The index to get the child from
  1180. */
  1181. PIXI.DisplayObjectContainer.prototype.removeChildAt = function(index)
  1182. {
  1183. var child = this.getChildAt( index );
  1184. if(this.stage)
  1185. child.removeStageReference();
  1186. child.parent = undefined;
  1187. this.children.splice( index, 1 );
  1188. return child;
  1189. };
  1190. /**
  1191. * Removes all child instances from the child list of the container.
  1192. *
  1193. * @method removeChildren
  1194. * @param beginIndex {Number} The beginning position. Predefined value is 0.
  1195. * @param endIndex {Number} The ending position. Predefined value is children's array length.
  1196. */
  1197. PIXI.DisplayObjectContainer.prototype.removeChildren = function(beginIndex, endIndex)
  1198. {
  1199. var begin = beginIndex || 0;
  1200. var end = typeof endIndex === 'number' ? endIndex : this.children.length;
  1201. var range = end - begin;
  1202. if (range > 0 && range <= end)
  1203. {
  1204. var removed = this.children.splice(begin, range);
  1205. for (var i = 0; i < removed.length; i++) {
  1206. var child = removed[i];
  1207. if(this.stage)
  1208. child.removeStageReference();
  1209. child.parent = undefined;
  1210. }
  1211. return removed;
  1212. }
  1213. else
  1214. {
  1215. throw new Error( 'Range Error, numeric values are outside the acceptable range' );
  1216. }
  1217. };
  1218. /*
  1219. * Updates the container's childrens transform for rendering
  1220. *
  1221. * @method updateTransform
  1222. * @private
  1223. */
  1224. PIXI.DisplayObjectContainer.prototype.updateTransform = function()
  1225. {
  1226. //this._currentBounds = null;
  1227. if(!this.visible)return;
  1228. PIXI.DisplayObject.prototype.updateTransform.call( this );
  1229. if(this._cacheAsBitmap)return;
  1230. for(var i=0,j=this.children.length; i<j; i++)
  1231. {
  1232. this.children[i].updateTransform();
  1233. }
  1234. };
  1235. /**
  1236. * Retrieves the bounds of the displayObjectContainer as a rectangle object
  1237. *
  1238. * @method getBounds
  1239. * @return {Rectangle} the rectangular bounding area
  1240. */
  1241. PIXI.DisplayObjectContainer.prototype.getBounds = function(matrix)
  1242. {
  1243. if(this.children.length === 0)return PIXI.EmptyRectangle;
  1244. // TODO the bounds have already been calculated this render session so return what we have
  1245. if(matrix)
  1246. {
  1247. var matrixCache = this.worldTransform;
  1248. this.worldTransform = matrix;
  1249. this.updateTransform();
  1250. this.worldTransform = matrixCache;
  1251. }
  1252. var minX = Infinity;
  1253. var minY = Infinity;
  1254. var maxX = -Infinity;
  1255. var maxY = -Infinity;
  1256. var childBounds;
  1257. var childMaxX;
  1258. var childMaxY;
  1259. var childVisible = false;
  1260. for(var i=0,j=this.children.length; i<j; i++)
  1261. {
  1262. var child = this.children[i];
  1263. if(!child.visible)continue;
  1264. childVisible = true;
  1265. childBounds = this.children[i].getBounds( matrix );
  1266. minX = minX < childBounds.x ? minX : childBounds.x;
  1267. minY = minY < childBounds.y ? minY : childBounds.y;
  1268. childMaxX = childBounds.width + childBounds.x;
  1269. childMaxY = childBounds.height + childBounds.y;
  1270. maxX = maxX > childMaxX ? maxX : childMaxX;
  1271. maxY = maxY > childMaxY ? maxY : childMaxY;
  1272. }
  1273. if(!childVisible)
  1274. return PIXI.EmptyRectangle;
  1275. var bounds = this._bounds;
  1276. bounds.x = minX;
  1277. bounds.y = minY;
  1278. bounds.width = maxX - minX;
  1279. bounds.height = maxY - minY;
  1280. // TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  1281. //this._currentBounds = bounds;
  1282. return bounds;
  1283. };
  1284. PIXI.DisplayObjectContainer.prototype.getLocalBounds = function()
  1285. {
  1286. var matrixCache = this.worldTransform;
  1287. this.worldTransform = PIXI.identityMatrix;
  1288. for(var i=0,j=this.children.length; i<j; i++)
  1289. {
  1290. this.children[i].updateTransform();
  1291. }
  1292. var bounds = this.getBounds();
  1293. this.worldTransform = matrixCache;
  1294. return bounds;
  1295. };
  1296. /**
  1297. * Sets the container's stage reference, the stage this object is connected to
  1298. *
  1299. * @method setStageReference
  1300. * @param stage {Stage} the stage that the container will have as its current stage reference
  1301. */
  1302. PIXI.DisplayObjectContainer.prototype.setStageReference = function(stage)
  1303. {
  1304. this.stage = stage;
  1305. if(this._interactive)this.stage.dirty = true;
  1306. for(var i=0,j=this.children.length; i<j; i++)
  1307. {
  1308. var child = this.children[i];
  1309. child.setStageReference(stage);
  1310. }
  1311. };
  1312. /**
  1313. * removes the current stage reference of the container
  1314. *
  1315. * @method removeStageReference
  1316. */
  1317. PIXI.DisplayObjectContainer.prototype.removeStageReference = function()
  1318. {
  1319. for(var i=0,j=this.children.length; i<j; i++)
  1320. {
  1321. var child = this.children[i];
  1322. child.removeStageReference();
  1323. }
  1324. if(this._interactive)this.stage.dirty = true;
  1325. this.stage = null;
  1326. };
  1327. /**
  1328. * Renders the object using the WebGL renderer
  1329. *
  1330. * @method _renderWebGL
  1331. * @param renderSession {RenderSession}
  1332. * @private
  1333. */
  1334. PIXI.DisplayObjectContainer.prototype._renderWebGL = function(renderSession)
  1335. {
  1336. if(!this.visible || this.alpha <= 0)return;
  1337. if(this._cacheAsBitmap)
  1338. {
  1339. this._renderCachedSprite(renderSession);
  1340. return;
  1341. }
  1342. var i,j;
  1343. if(this._mask || this._filters)
  1344. {
  1345. if(this._mask)
  1346. {
  1347. renderSession.spriteBatch.stop();
  1348. renderSession.maskManager.pushMask(this.mask, renderSession);
  1349. renderSession.spriteBatch.start();
  1350. }
  1351. if(this._filters)
  1352. {
  1353. renderSession.spriteBatch.flush();
  1354. renderSession.filterManager.pushFilter(this._filterBlock);
  1355. }
  1356. // simple render children!
  1357. for(i=0,j=this.children.length; i<j; i++)
  1358. {
  1359. this.children[i]._renderWebGL(renderSession);
  1360. }
  1361. renderSession.spriteBatch.stop();
  1362. if(this._filters)renderSession.filterManager.popFilter();
  1363. if(this._mask)renderSession.maskManager.popMask(renderSession);
  1364. renderSession.spriteBatch.start();
  1365. }
  1366. else
  1367. {
  1368. // simple render children!
  1369. for(i=0,j=this.children.length; i<j; i++)
  1370. {
  1371. this.children[i]._renderWebGL(renderSession);
  1372. }
  1373. }
  1374. };
  1375. /**
  1376. * Renders the object using the Canvas renderer
  1377. *
  1378. * @method _renderCanvas
  1379. * @param renderSession {RenderSession}
  1380. * @private
  1381. */
  1382. PIXI.DisplayObjectContainer.prototype._renderCanvas = function(renderSession)
  1383. {
  1384. if(this.visible === false || this.alpha === 0)return;
  1385. if(this._cacheAsBitmap)
  1386. {
  1387. this._renderCachedSprite(renderSession);
  1388. return;
  1389. }
  1390. if(this._mask)
  1391. {
  1392. renderSession.maskManager.pushMask(this._mask, renderSession.context);
  1393. }
  1394. for(var i=0,j=this.children.length; i<j; i++)
  1395. {
  1396. var child = this.children[i];
  1397. child._renderCanvas(renderSession);
  1398. }
  1399. if(this._mask)
  1400. {
  1401. renderSession.maskManager.popMask(renderSession.context);
  1402. }
  1403. };
  1404. /**
  1405. * @author Mat Groves http://matgroves.com/ @Doormat23
  1406. */
  1407. /**
  1408. * The Sprite object is the base for all textured objects that are rendered to the screen
  1409. *
  1410. * @class Sprite
  1411. * @extends DisplayObjectContainer
  1412. * @constructor
  1413. * @param texture {Texture} The texture for this sprite
  1414. *
  1415. * A sprite can be created directly from an image like this :
  1416. * var sprite = nex PIXI.Sprite.FromImage('assets/image.png');
  1417. * yourStage.addChild(sprite);
  1418. * then obviously don't forget to add it to the stage you have already created
  1419. */
  1420. PIXI.Sprite = function(texture)
  1421. {
  1422. PIXI.DisplayObjectContainer.call( this );
  1423. /**
  1424. * The anchor sets the origin point of the texture.
  1425. * The default is 0,0 this means the texture's origin is the top left
  1426. * Setting than anchor to 0.5,0.5 means the textures origin is centred
  1427. * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner
  1428. *
  1429. * @property anchor
  1430. * @type Point
  1431. */
  1432. this.anchor = new PIXI.Point();
  1433. /**
  1434. * The texture that the sprite is using
  1435. *
  1436. * @property texture
  1437. * @type Texture
  1438. */
  1439. this.texture = texture;
  1440. /**
  1441. * The width of the sprite (this is initially set by the texture)
  1442. *
  1443. * @property _width
  1444. * @type Number
  1445. * @private
  1446. */
  1447. this._width = 0;
  1448. /**
  1449. * The height of the sprite (this is initially set by the texture)
  1450. *
  1451. * @property _height
  1452. * @type Number
  1453. * @private
  1454. */
  1455. this._height = 0;
  1456. /**
  1457. * The tint applied to the sprite. This is a hex value
  1458. *
  1459. * @property tint
  1460. * @type Number
  1461. * @default 0xFFFFFF
  1462. */
  1463. this.tint = 0xFFFFFF;// * Math.random();
  1464. /**
  1465. * The blend mode to be applied to the sprite
  1466. *
  1467. * @property blendMode
  1468. * @type Number
  1469. * @default PIXI.blendModes.NORMAL;
  1470. */
  1471. this.blendMode = PIXI.blendModes.NORMAL;
  1472. if(texture.baseTexture.hasLoaded)
  1473. {
  1474. this.onTextureUpdate();
  1475. }
  1476. else
  1477. {
  1478. this.onTextureUpdateBind = this.onTextureUpdate.bind(this);
  1479. this.texture.addEventListener( 'update', this.onTextureUpdateBind );
  1480. }
  1481. this.renderable = true;
  1482. };
  1483. // constructor
  1484. PIXI.Sprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
  1485. PIXI.Sprite.prototype.constructor = PIXI.Sprite;
  1486. /**
  1487. * The width of the sprite, setting this will actually modify the scale to achieve the value set
  1488. *
  1489. * @property width
  1490. * @type Number
  1491. */
  1492. Object.defineProperty(PIXI.Sprite.prototype, 'width', {
  1493. get: function() {
  1494. return this.scale.x * this.texture.frame.width;
  1495. },
  1496. set: function(value) {
  1497. this.scale.x = value / this.texture.frame.width;
  1498. this._width = value;
  1499. }
  1500. });
  1501. /**
  1502. * The height of the sprite, setting this will actually modify the scale to achieve the value set
  1503. *
  1504. * @property height
  1505. * @type Number
  1506. */
  1507. Object.defineProperty(PIXI.Sprite.prototype, 'height', {
  1508. get: function() {
  1509. return this.scale.y * this.texture.frame.height;
  1510. },
  1511. set: function(value) {
  1512. this.scale.y = value / this.texture.frame.height;
  1513. this._height = value;
  1514. }
  1515. });
  1516. /**
  1517. * Sets the texture of the sprite
  1518. *
  1519. * @method setTexture
  1520. * @param texture {Texture} The PIXI texture that is displayed by the sprite
  1521. */
  1522. PIXI.Sprite.prototype.setTexture = function(texture)
  1523. {
  1524. // stop current texture;
  1525. if(this.texture.baseTexture !== texture.baseTexture)
  1526. {
  1527. this.textureChange = true;
  1528. this.texture = texture;
  1529. }
  1530. else
  1531. {
  1532. this.texture = texture;
  1533. }
  1534. this.cachedTint = 0xFFFFFF;
  1535. this.updateFrame = true;
  1536. };
  1537. /**
  1538. * When the texture is updated, this event will fire to update the scale and frame
  1539. *
  1540. * @method onTextureUpdate
  1541. * @param event
  1542. * @private
  1543. */
  1544. PIXI.Sprite.prototype.onTextureUpdate = function()
  1545. {
  1546. // so if _width is 0 then width was not set..
  1547. if(this._width)this.scale.x = this._width / this.texture.frame.width;
  1548. if(this._height)this.scale.y = this._height / this.texture.frame.height;
  1549. this.updateFrame = true;
  1550. };
  1551. /**
  1552. * Returns the framing rectangle of the sprite as a PIXI.Rectangle object
  1553. *
  1554. * @method getBounds
  1555. * @param matrix {Matrix} the transformation matrix of the sprite
  1556. * @return {Rectangle} the framing rectangle
  1557. */
  1558. PIXI.Sprite.prototype.getBounds = function(matrix)
  1559. {
  1560. var width = this.texture.frame.width;
  1561. var height = this.texture.frame.height;
  1562. var w0 = width * (1-this.anchor.x);
  1563. var w1 = width * -this.anchor.x;
  1564. var h0 = height * (1-this.anchor.y);
  1565. var h1 = height * -this.anchor.y;
  1566. var worldTransform = matrix || this.worldTransform ;
  1567. var a = worldTransform.a;
  1568. var b = worldTransform.c;
  1569. var c = worldTransform.b;
  1570. var d = worldTransform.d;
  1571. var tx = worldTransform.tx;
  1572. var ty = worldTransform.ty;
  1573. var x1 = a * w1 + c * h1 + tx;
  1574. var y1 = d * h1 + b * w1 + ty;
  1575. var x2 = a * w0 + c * h1 + tx;
  1576. var y2 = d * h1 + b * w0 + ty;
  1577. var x3 = a * w0 + c * h0 + tx;
  1578. var y3 = d * h0 + b * w0 + ty;
  1579. var x4 = a * w1 + c * h0 + tx;
  1580. var y4 = d * h0 + b * w1 + ty;
  1581. var maxX = -Infinity;
  1582. var maxY = -Infinity;
  1583. var minX = Infinity;
  1584. var minY = Infinity;
  1585. minX = x1 < minX ? x1 : minX;
  1586. minX = x2 < minX ? x2 : minX;
  1587. minX = x3 < minX ? x3 : minX;
  1588. minX = x4 < minX ? x4 : minX;
  1589. minY = y1 < minY ? y1 : minY;
  1590. minY = y2 < minY ? y2 : minY;
  1591. minY = y3 < minY ? y3 : minY;
  1592. minY = y4 < minY ? y4 : minY;
  1593. maxX = x1 > maxX ? x1 : maxX;
  1594. maxX = x2 > maxX ? x2 : maxX;
  1595. maxX = x3 > maxX ? x3 : maxX;
  1596. maxX = x4 > maxX ? x4 : maxX;
  1597. maxY = y1 > maxY ? y1 : maxY;
  1598. maxY = y2 > maxY ? y2 : maxY;
  1599. maxY = y3 > maxY ? y3 : maxY;
  1600. maxY = y4 > maxY ? y4 : maxY;
  1601. var bounds = this._bounds;
  1602. bounds.x = minX;
  1603. bounds.width = maxX - minX;
  1604. bounds.y = minY;
  1605. bounds.height = maxY - minY;
  1606. // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  1607. this._currentBounds = bounds;
  1608. return bounds;
  1609. };
  1610. /**
  1611. * Renders the object using the WebGL renderer
  1612. *
  1613. * @method _renderWebGL
  1614. * @param renderSession {RenderSession}
  1615. * @private
  1616. */
  1617. PIXI.Sprite.prototype._renderWebGL = function(renderSession)
  1618. {
  1619. // if the sprite is not visible or the alpha is 0 then no need to render this element
  1620. if(!this.visible || this.alpha <= 0)return;
  1621. var i,j;
  1622. // do a quick check to see if this element has a mask or a filter.
  1623. if(this._mask || this._filters)
  1624. {
  1625. var spriteBatch = renderSession.spriteBatch;
  1626. if(this._mask)
  1627. {
  1628. spriteBatch.stop();
  1629. renderSession.maskManager.pushMask(this.mask, renderSession);
  1630. spriteBatch.start();
  1631. }
  1632. if(this._filters)
  1633. {
  1634. spriteBatch.flush();
  1635. renderSession.filterManager.pushFilter(this._filterBlock);
  1636. }
  1637. // add this sprite to the batch
  1638. spriteBatch.render(this);
  1639. // now loop through the children and make sure they get rendered
  1640. for(i=0,j=this.children.length; i<j; i++)
  1641. {
  1642. this.children[i]._renderWebGL(renderSession);
  1643. }
  1644. // time to stop the sprite batch as either a mask element or a filter draw will happen next
  1645. spriteBatch.stop();
  1646. if(this._filters)renderSession.filterManager.popFilter();
  1647. if(this._mask)renderSession.maskManager.popMask(renderSession);
  1648. spriteBatch.start();
  1649. }
  1650. else
  1651. {
  1652. renderSession.spriteBatch.render(this);
  1653. // simple render children!
  1654. for(i=0,j=this.children.length; i<j; i++)
  1655. {
  1656. this.children[i]._renderWebGL(renderSession);
  1657. }
  1658. }
  1659. //TODO check culling
  1660. };
  1661. /**
  1662. * Renders the object using the Canvas renderer
  1663. *
  1664. * @method _renderCanvas
  1665. * @param renderSession {RenderSession}
  1666. * @private
  1667. */
  1668. PIXI.Sprite.prototype._renderCanvas = function(renderSession)
  1669. {
  1670. // if the sprite is not visible or the alpha is 0 then no need to render this element
  1671. if(this.visible === false || this.alpha === 0)return;
  1672. var frame = this.texture.frame;
  1673. var context = renderSession.context;
  1674. var texture = this.texture;
  1675. if(this.blendMode !== renderSession.currentBlendMode)
  1676. {
  1677. renderSession.currentBlendMode = this.blendMode;
  1678. context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  1679. }
  1680. if(this._mask)
  1681. {
  1682. renderSession.maskManager.pushMask(this._mask, renderSession.context);
  1683. }
  1684. //ignore null sources
  1685. if(frame && frame.width && frame.height && texture.baseTexture.source)
  1686. {
  1687. context.globalAlpha = this.worldAlpha;
  1688. var transform = this.worldTransform;
  1689. // allow for trimming
  1690. if (renderSession.roundPixels)
  1691. {
  1692. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0);
  1693. }
  1694. else
  1695. {
  1696. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
  1697. }
  1698. //if smoothingEnabled is supported and we need to change the smoothing property for this texture
  1699. if(renderSession.smoothProperty && renderSession.scaleMode !== this.texture.baseTexture.scaleMode) {
  1700. renderSession.scaleMode = this.texture.baseTexture.scaleMode;
  1701. context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR);
  1702. }
  1703. if(this.tint !== 0xFFFFFF)
  1704. {
  1705. if(this.cachedTint !== this.tint)
  1706. {
  1707. // no point tinting an image that has not loaded yet!
  1708. if(!texture.baseTexture.hasLoaded)return;
  1709. this.cachedTint = this.tint;
  1710. //TODO clean up caching - how to clean up the caches?
  1711. this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
  1712. }
  1713. context.drawImage(this.tintedTexture,
  1714. 0,
  1715. 0,
  1716. frame.width,
  1717. frame.height,
  1718. (this.anchor.x) * -frame.width,
  1719. (this.anchor.y) * -frame.height,
  1720. frame.width,
  1721. frame.height);
  1722. }
  1723. else
  1724. {
  1725. if(texture.trim)
  1726. {
  1727. var trim = texture.trim;
  1728. context.drawImage(this.texture.baseTexture.source,
  1729. frame.x,
  1730. frame.y,
  1731. frame.width,
  1732. frame.height,
  1733. trim.x - this.anchor.x * trim.width,
  1734. trim.y - this.anchor.y * trim.height,
  1735. frame.width,
  1736. frame.height);
  1737. }
  1738. else
  1739. {
  1740. context.drawImage(this.texture.baseTexture.source,
  1741. frame.x,
  1742. frame.y,
  1743. frame.width,
  1744. frame.height,
  1745. (this.anchor.x) * -frame.width,
  1746. (this.anchor.y) * -frame.height,
  1747. frame.width,
  1748. frame.height);
  1749. }
  1750. }
  1751. }
  1752. // OVERWRITE
  1753. for(var i=0,j=this.children.length; i<j; i++)
  1754. {
  1755. var child = this.children[i];
  1756. child._renderCanvas(renderSession);
  1757. }
  1758. if(this._mask)
  1759. {
  1760. renderSession.maskManager.popMask(renderSession.context);
  1761. }
  1762. };
  1763. // some helper functions..
  1764. /**
  1765. *
  1766. * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
  1767. * The frame ids are created when a Texture packer file has been loaded
  1768. *
  1769. * @method fromFrame
  1770. * @static
  1771. * @param frameId {String} The frame Id of the texture in the cache
  1772. * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId
  1773. */
  1774. PIXI.Sprite.fromFrame = function(frameId)
  1775. {
  1776. var texture = PIXI.TextureCache[frameId];
  1777. if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this);
  1778. return new PIXI.Sprite(texture);
  1779. };
  1780. /**
  1781. *
  1782. * Helper function that creates a sprite that will contain a texture based on an image url
  1783. * If the image is not in the texture cache it will be loaded
  1784. *
  1785. * @method fromImage
  1786. * @static
  1787. * @param imageId {String} The image url of the texture
  1788. * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id
  1789. */
  1790. PIXI.Sprite.fromImage = function(imageId, crossorigin, scaleMode)
  1791. {
  1792. var texture = PIXI.Texture.fromImage(imageId, crossorigin, scaleMode);
  1793. return new PIXI.Sprite(texture);
  1794. };
  1795. /**
  1796. * @author Mat Groves http://matgroves.com/
  1797. */
  1798. /**
  1799. * The SpriteBatch class is a really fast version of the DisplayObjectContainer
  1800. * built solely for speed, so use when you need a lot of sprites or particles.
  1801. * And it's extremely easy to use :
  1802. var container = new PIXI.SpriteBatch();
  1803. stage.addChild(container);
  1804. for(var i = 0; i < 100; i++)
  1805. {
  1806. var sprite = new PIXI.Sprite.fromImage("myImage.png");
  1807. container.addChild(sprite);
  1808. }
  1809. * And here you have a hundred sprites that will be renderer at the speed of light
  1810. *
  1811. * @class SpriteBatch
  1812. * @constructor
  1813. * @param texture {Texture}
  1814. */
  1815. PIXI.SpriteBatch = function(texture)
  1816. {
  1817. PIXI.DisplayObjectContainer.call( this);
  1818. this.textureThing = texture;
  1819. this.ready = false;
  1820. };
  1821. PIXI.SpriteBatch.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  1822. PIXI.SpriteBatch.constructor = PIXI.SpriteBatch;
  1823. /*
  1824. * Initialises the spriteBatch
  1825. *
  1826. * @method initWebGL
  1827. * @param gl {WebGLContext} the current WebGL drawing context
  1828. */
  1829. PIXI.SpriteBatch.prototype.initWebGL = function(gl)
  1830. {
  1831. // TODO only one needed for the whole engine really?
  1832. this.fastSpriteBatch = new PIXI.WebGLFastSpriteBatch(gl);
  1833. this.ready = true;
  1834. };
  1835. /*
  1836. * Updates the object transform for rendering
  1837. *
  1838. * @method updateTransform
  1839. * @private
  1840. */
  1841. PIXI.SpriteBatch.prototype.updateTransform = function()
  1842. {
  1843. // TODO dont need to!
  1844. PIXI.DisplayObject.prototype.updateTransform.call( this );
  1845. // PIXI.DisplayObjectContainer.prototype.updateTransform.call( this );
  1846. };
  1847. /**
  1848. * Renders the object using the WebGL renderer
  1849. *
  1850. * @method _renderWebGL
  1851. * @param renderSession {RenderSession}
  1852. * @private
  1853. */
  1854. PIXI.SpriteBatch.prototype._renderWebGL = function(renderSession)
  1855. {
  1856. if(!this.visible || this.alpha <= 0 || !this.children.length)return;
  1857. if(!this.ready)this.initWebGL( renderSession.gl );
  1858. renderSession.spriteBatch.stop();
  1859. renderSession.shaderManager.activateShader(renderSession.shaderManager.fastShader);
  1860. this.fastSpriteBatch.begin(this, renderSession);
  1861. this.fastSpriteBatch.render(this);
  1862. renderSession.shaderManager.activateShader(renderSession.shaderManager.defaultShader);
  1863. renderSession.spriteBatch.start();
  1864. };
  1865. /**
  1866. * Renders the object using the Canvas renderer
  1867. *
  1868. * @method _renderCanvas
  1869. * @param renderSession {RenderSession}
  1870. * @private
  1871. */
  1872. PIXI.SpriteBatch.prototype._renderCanvas = function(renderSession)
  1873. {
  1874. var context = renderSession.context;
  1875. context.globalAlpha = this.worldAlpha;
  1876. PIXI.DisplayObject.prototype.updateTransform.call(this);
  1877. var transform = this.worldTransform;
  1878. // alow for trimming
  1879. var isRotated = true;
  1880. for (var i = 0; i < this.children.length; i++) {
  1881. var child = this.children[i];
  1882. if(!child.visible)continue;
  1883. var texture = child.texture;
  1884. var frame = texture.frame;
  1885. context.globalAlpha = this.worldAlpha * child.alpha;
  1886. if(child.rotation % (Math.PI * 2) === 0)
  1887. {
  1888. if(isRotated)
  1889. {
  1890. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
  1891. isRotated = false;
  1892. }
  1893. // this is the fastest way to optimise! - if rotation is 0 then we can avoid any kind of setTransform call
  1894. context.drawImage(texture.baseTexture.source,
  1895. frame.x,
  1896. frame.y,
  1897. frame.width,
  1898. frame.height,
  1899. ((child.anchor.x) * (-frame.width * child.scale.x) + child.position.x + 0.5) | 0,
  1900. ((child.anchor.y) * (-frame.height * child.scale.y) + child.position.y + 0.5) | 0,
  1901. frame.width * child.scale.x,
  1902. frame.height * child.scale.y);
  1903. }
  1904. else
  1905. {
  1906. if(!isRotated)isRotated = true;
  1907. PIXI.DisplayObject.prototype.updateTransform.call(child);
  1908. var childTransform = child.worldTransform;
  1909. // allow for trimming
  1910. if (renderSession.roundPixels)
  1911. {
  1912. context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0);
  1913. }
  1914. else
  1915. {
  1916. context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty);
  1917. }
  1918. context.drawImage(texture.baseTexture.source,
  1919. frame.x,
  1920. frame.y,
  1921. frame.width,
  1922. frame.height,
  1923. ((child.anchor.x) * (-frame.width) + 0.5) | 0,
  1924. ((child.anchor.y) * (-frame.height) + 0.5) | 0,
  1925. frame.width,
  1926. frame.height);
  1927. }
  1928. // context.restore();
  1929. }
  1930. // context.restore();
  1931. };
  1932. /**
  1933. * @author Mat Groves http://matgroves.com/ @Doormat23
  1934. */
  1935. PIXI.FilterBlock = function()
  1936. {
  1937. this.visible = true;
  1938. this.renderable = true;
  1939. };
  1940. /**
  1941. * @author Mat Groves http://matgroves.com/ @Doormat23
  1942. * - Modified by Tom Slezakowski http://www.tomslezakowski.com @TomSlezakowski (24/03/2014) - Added dropShadowColor.
  1943. */
  1944. /**
  1945. * A Text Object will create a line(s) of text. To split a line you can use '\n'
  1946. * or add a wordWrap property set to true and and wordWrapWidth property with a value
  1947. * in the style object
  1948. *
  1949. * @class Text
  1950. * @extends Sprite
  1951. * @constructor
  1952. * @param text {String} The copy that you would like the text to display
  1953. * @param [style] {Object} The style parameters
  1954. * @param [style.font] {String} default 'bold 20px Arial' The style and size of the font
  1955. * @param [style.fill='black'] {String|Number} A canvas fillstyle that will be used on the text e.g 'red', '#00FF00'
  1956. * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
  1957. * @param [style.stroke] {String|Number} A canvas fillstyle that will be used on the text stroke e.g 'blue', '#FCFF00'
  1958. * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
  1959. * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
  1960. * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap, it needs wordWrap to be set to true
  1961. * @param [style.dropShadow=false] {Boolean} Set a drop shadow for the text
  1962. * @param [style.dropShadowColor='#000000'] {String} A fill style to be used on the dropshadow e.g 'red', '#00FF00'
  1963. * @param [style.dropShadowAngle=Math.PI/4] {Number} Set a angle of the drop shadow
  1964. * @param [style.dropShadowDistance=5] {Number} Set a distance of the drop shadow
  1965. */
  1966. PIXI.Text = function(text, style)
  1967. {
  1968. /**
  1969. * The canvas element that everything is drawn to
  1970. *
  1971. * @property canvas
  1972. * @type HTMLCanvasElement
  1973. */
  1974. this.canvas = document.createElement('canvas');
  1975. /**
  1976. * The canvas 2d context that everything is drawn with
  1977. * @property context
  1978. * @type HTMLCanvasElement 2d Context
  1979. */
  1980. this.context = this.canvas.getContext('2d');
  1981. PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas));
  1982. this.setText(text);
  1983. this.setStyle(style);
  1984. this.updateText();
  1985. this.dirty = false;
  1986. };
  1987. // constructor
  1988. PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype);
  1989. PIXI.Text.prototype.constructor = PIXI.Text;
  1990. /**
  1991. * Set the style of the text
  1992. *
  1993. * @method setStyle
  1994. * @param [style] {Object} The style parameters
  1995. * @param [style.font='bold 20pt Arial'] {String} The style and size of the font
  1996. * @param [style.fill='black'] {Object} A canvas fillstyle that will be used on the text eg 'red', '#00FF00'
  1997. * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
  1998. * @param [style.stroke='black'] {String} A canvas fillstyle that will be used on the text stroke eg 'blue', '#FCFF00'
  1999. * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke)
  2000. * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used
  2001. * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap
  2002. * @param [style.dropShadow=false] {Boolean} Set a drop shadow for the text
  2003. * @param [style.dropShadowColor='#000000'] {String} A fill style to be used on the dropshadow e.g 'red', '#00FF00'
  2004. * @param [style.dropShadowAngle=Math.PI/4] {Number} Set a angle of the drop shadow
  2005. * @param [style.dropShadowDistance=5] {Number} Set a distance of the drop shadow
  2006. */
  2007. PIXI.Text.prototype.setStyle = function(style)
  2008. {
  2009. style = style || {};
  2010. style.font = style.font || 'bold 20pt Arial';
  2011. style.fill = style.fill || 'black';
  2012. style.align = style.align || 'left';
  2013. style.stroke = style.stroke || 'black'; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
  2014. style.strokeThickness = style.strokeThickness || 0;
  2015. style.wordWrap = style.wordWrap || false;
  2016. style.wordWrapWidth = style.wordWrapWidth || 100;
  2017. style.wordWrapWidth = style.wordWrapWidth || 100;
  2018. style.dropShadow = style.dropShadow || false;
  2019. style.dropShadowAngle = style.dropShadowAngle || Math.PI / 6;
  2020. style.dropShadowDistance = style.dropShadowDistance || 4;
  2021. style.dropShadowColor = style.dropShadowColor || 'black';
  2022. this.style = style;
  2023. this.dirty = true;
  2024. };
  2025. /**
  2026. * Set the copy for the text object. To split a line you can use '\n'
  2027. *
  2028. * @method setText
  2029. * @param {String} text The copy that you would like the text to display
  2030. */
  2031. PIXI.Text.prototype.setText = function(text)
  2032. {
  2033. this.text = text.toString() || ' ';
  2034. this.dirty = true;
  2035. };
  2036. /**
  2037. * Renders text and updates it when needed
  2038. *
  2039. * @method updateText
  2040. * @private
  2041. */
  2042. PIXI.Text.prototype.updateText = function()
  2043. {
  2044. this.context.font = this.style.font;
  2045. var outputText = this.text;
  2046. // word wrap
  2047. // preserve original text
  2048. if(this.style.wordWrap)outputText = this.wordWrap(this.text);
  2049. //split text into lines
  2050. var lines = outputText.split(/(?:\r\n|\r|\n)/);
  2051. //calculate text width
  2052. var lineWidths = [];
  2053. var maxLineWidth = 0;
  2054. for (var i = 0; i < lines.length; i++)
  2055. {
  2056. var lineWidth = this.context.measureText(lines[i]).width;
  2057. lineWidths[i] = lineWidth;
  2058. maxLineWidth = Math.max(maxLineWidth, lineWidth);
  2059. }
  2060. var width = maxLineWidth + this.style.strokeThickness;
  2061. if(this.style.dropShadow)width += this.style.dropShadowDistance;
  2062. this.canvas.width = width;
  2063. //calculate text height
  2064. var lineHeight = this.determineFontHeight('font: ' + this.style.font + ';') + this.style.strokeThickness;
  2065. var height = lineHeight * lines.length;
  2066. if(this.style.dropShadow)height += this.style.dropShadowDistance;
  2067. this.canvas.height = height;
  2068. if(navigator.isCocoonJS) this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
  2069. this.context.font = this.style.font;
  2070. this.context.strokeStyle = this.style.stroke;
  2071. this.context.lineWidth = this.style.strokeThickness;
  2072. this.context.textBaseline = 'top';
  2073. var linePositionX;
  2074. var linePositionY;
  2075. if(this.style.dropShadow)
  2076. {
  2077. this.context.fillStyle = this.style.dropShadowColor;
  2078. var xShadowOffset = Math.sin(this.style.dropShadowAngle) * this.style.dropShadowDistance;
  2079. var yShadowOffset = Math.cos(this.style.dropShadowAngle) * this.style.dropShadowDistance;
  2080. for (i = 0; i < lines.length; i++)
  2081. {
  2082. linePositionX = this.style.strokeThickness / 2;
  2083. linePositionY = this.style.strokeThickness / 2 + i * lineHeight;
  2084. if(this.style.align === 'right')
  2085. {
  2086. linePositionX += maxLineWidth - lineWidths[i];
  2087. }
  2088. else if(this.style.align === 'center')
  2089. {
  2090. linePositionX += (maxLineWidth - lineWidths[i]) / 2;
  2091. }
  2092. if(this.style.fill)
  2093. {
  2094. this.context.fillText(lines[i], linePositionX + xShadowOffset, linePositionY + yShadowOffset);
  2095. }
  2096. // if(dropShadow)
  2097. }
  2098. }
  2099. //set canvas text styles
  2100. this.context.fillStyle = this.style.fill;
  2101. //draw lines line by line
  2102. for (i = 0; i < lines.length; i++)
  2103. {
  2104. linePositionX = this.style.strokeThickness / 2;
  2105. linePositionY = this.style.strokeThickness / 2 + i * lineHeight;
  2106. if(this.style.align === 'right')
  2107. {
  2108. linePositionX += maxLineWidth - lineWidths[i];
  2109. }
  2110. else if(this.style.align === 'center')
  2111. {
  2112. linePositionX += (maxLineWidth - lineWidths[i]) / 2;
  2113. }
  2114. if(this.style.stroke && this.style.strokeThickness)
  2115. {
  2116. this.context.strokeText(lines[i], linePositionX, linePositionY);
  2117. }
  2118. if(this.style.fill)
  2119. {
  2120. this.context.fillText(lines[i], linePositionX, linePositionY);
  2121. }
  2122. // if(dropShadow)
  2123. }
  2124. this.updateTexture();
  2125. };
  2126. /**
  2127. * Updates texture size based on canvas size
  2128. *
  2129. * @method updateTexture
  2130. * @private
  2131. */
  2132. PIXI.Text.prototype.updateTexture = function()
  2133. {
  2134. this.texture.baseTexture.width = this.canvas.width;
  2135. this.texture.baseTexture.height = this.canvas.height;
  2136. this.texture.frame.width = this.canvas.width;
  2137. this.texture.frame.height = this.canvas.height;
  2138. this._width = this.canvas.width;
  2139. this._height = this.canvas.height;
  2140. this.requiresUpdate = true;
  2141. };
  2142. /**
  2143. * Renders the object using the WebGL renderer
  2144. *
  2145. * @method _renderWebGL
  2146. * @param renderSession {RenderSession}
  2147. * @private
  2148. */
  2149. PIXI.Text.prototype._renderWebGL = function(renderSession)
  2150. {
  2151. if(this.requiresUpdate)
  2152. {
  2153. this.requiresUpdate = false;
  2154. PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl);
  2155. }
  2156. PIXI.Sprite.prototype._renderWebGL.call(this, renderSession);
  2157. };
  2158. /**
  2159. * Updates the transform of this object
  2160. *
  2161. * @method updateTransform
  2162. * @private
  2163. */
  2164. PIXI.Text.prototype.updateTransform = function()
  2165. {
  2166. if(this.dirty)
  2167. {
  2168. this.updateText();
  2169. this.dirty = false;
  2170. }
  2171. PIXI.Sprite.prototype.updateTransform.call(this);
  2172. };
  2173. /*
  2174. * http://stackoverflow.com/users/34441/ellisbben
  2175. * great solution to the problem!
  2176. * returns the height of the given font
  2177. *
  2178. * @method determineFontHeight
  2179. * @param fontStyle {Object}
  2180. * @private
  2181. */
  2182. PIXI.Text.prototype.determineFontHeight = function(fontStyle)
  2183. {
  2184. // build a little reference dictionary so if the font style has been used return a
  2185. // cached version...
  2186. var result = PIXI.Text.heightCache[fontStyle];
  2187. if(!result)
  2188. {
  2189. var body = document.getElementsByTagName('body')[0];
  2190. var dummy = document.createElement('div');
  2191. var dummyText = document.createTextNode('M');
  2192. dummy.appendChild(dummyText);
  2193. dummy.setAttribute('style', fontStyle + ';position:absolute;top:0;left:0');
  2194. body.appendChild(dummy);
  2195. result = dummy.offsetHeight;
  2196. PIXI.Text.heightCache[fontStyle] = result;
  2197. body.removeChild(dummy);
  2198. }
  2199. return result;
  2200. };
  2201. /**
  2202. * Applies newlines to a string to have it optimally fit into the horizontal
  2203. * bounds set by the Text object's wordWrapWidth property.
  2204. *
  2205. * @method wordWrap
  2206. * @param text {String}
  2207. * @private
  2208. */
  2209. PIXI.Text.prototype.wordWrap = function(text)
  2210. {
  2211. // Greedy wrapping algorithm that will wrap words as the line grows longer
  2212. // than its horizontal bounds.
  2213. var result = '';
  2214. var lines = text.split('\n');
  2215. for (var i = 0; i < lines.length; i++)
  2216. {
  2217. var spaceLeft = this.style.wordWrapWidth;
  2218. var words = lines[i].split(' ');
  2219. for (var j = 0; j < words.length; j++)
  2220. {
  2221. var wordWidth = this.context.measureText(words[j]).width;
  2222. var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width;
  2223. if(wordWidthWithSpace > spaceLeft)
  2224. {
  2225. // Skip printing the newline if it's the first word of the line that is
  2226. // greater than the word wrap width.
  2227. if(j > 0)
  2228. {
  2229. result += '\n';
  2230. }
  2231. result += words[j] + ' ';
  2232. spaceLeft = this.style.wordWrapWidth - wordWidth;
  2233. }
  2234. else
  2235. {
  2236. spaceLeft -= wordWidthWithSpace;
  2237. result += words[j] + ' ';
  2238. }
  2239. }
  2240. if (i < lines.length-1)
  2241. {
  2242. result += '\n';
  2243. }
  2244. }
  2245. return result;
  2246. };
  2247. /**
  2248. * Destroys this text object
  2249. *
  2250. * @method destroy
  2251. * @param destroyTexture {Boolean}
  2252. */
  2253. PIXI.Text.prototype.destroy = function(destroyTexture)
  2254. {
  2255. if(destroyTexture)
  2256. {
  2257. this.texture.destroy();
  2258. }
  2259. };
  2260. PIXI.Text.heightCache = {};
  2261. /**
  2262. * @author Mat Groves http://matgroves.com/ @Doormat23
  2263. */
  2264. /**
  2265. * 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'
  2266. * You can generate the fnt files using
  2267. * http://www.angelcode.com/products/bmfont/ for windows or
  2268. * http://www.bmglyph.com/ for mac.
  2269. *
  2270. * @class BitmapText
  2271. * @extends DisplayObjectContainer
  2272. * @constructor
  2273. * @param text {String} The copy that you would like the text to display
  2274. * @param style {Object} The style parameters
  2275. * @param style.font {String} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously)
  2276. * @param [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
  2277. */
  2278. PIXI.BitmapText = function(text, style)
  2279. {
  2280. PIXI.DisplayObjectContainer.call(this);
  2281. this._pool = [];
  2282. this.setText(text);
  2283. this.setStyle(style);
  2284. this.updateText();
  2285. this.dirty = false;
  2286. };
  2287. // constructor
  2288. PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  2289. PIXI.BitmapText.prototype.constructor = PIXI.BitmapText;
  2290. /**
  2291. * Set the copy for the text object
  2292. *
  2293. * @method setText
  2294. * @param text {String} The copy that you would like the text to display
  2295. */
  2296. PIXI.BitmapText.prototype.setText = function(text)
  2297. {
  2298. this.text = text || ' ';
  2299. this.dirty = true;
  2300. };
  2301. /**
  2302. * Set the style of the text
  2303. * style.font {String} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously)
  2304. * [style.align='left'] {String} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
  2305. *
  2306. * @method setStyle
  2307. * @param style {Object} The style parameters, contained as properties of an object
  2308. */
  2309. PIXI.BitmapText.prototype.setStyle = function(style)
  2310. {
  2311. style = style || {};
  2312. style.align = style.align || 'left';
  2313. this.style = style;
  2314. var font = style.font.split(' ');
  2315. this.fontName = font[font.length - 1];
  2316. this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size;
  2317. this.dirty = true;
  2318. this.tint = style.tint;
  2319. };
  2320. /**
  2321. * Renders text and updates it when needed
  2322. *
  2323. * @method updateText
  2324. * @private
  2325. */
  2326. PIXI.BitmapText.prototype.updateText = function()
  2327. {
  2328. var data = PIXI.BitmapText.fonts[this.fontName];
  2329. var pos = new PIXI.Point();
  2330. var prevCharCode = null;
  2331. var chars = [];
  2332. var maxLineWidth = 0;
  2333. var lineWidths = [];
  2334. var line = 0;
  2335. var scale = this.fontSize / data.size;
  2336. for(var i = 0; i < this.text.length; i++)
  2337. {
  2338. var charCode = this.text.charCodeAt(i);
  2339. if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i)))
  2340. {
  2341. lineWidths.push(pos.x);
  2342. maxLineWidth = Math.max(maxLineWidth, pos.x);
  2343. line++;
  2344. pos.x = 0;
  2345. pos.y += data.lineHeight;
  2346. prevCharCode = null;
  2347. continue;
  2348. }
  2349. var charData = data.chars[charCode];
  2350. if(!charData) continue;
  2351. if(prevCharCode && charData[prevCharCode])
  2352. {
  2353. pos.x += charData.kerning[prevCharCode];
  2354. }
  2355. chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)});
  2356. pos.x += charData.xAdvance;
  2357. prevCharCode = charCode;
  2358. }
  2359. lineWidths.push(pos.x);
  2360. maxLineWidth = Math.max(maxLineWidth, pos.x);
  2361. var lineAlignOffsets = [];
  2362. for(i = 0; i <= line; i++)
  2363. {
  2364. var alignOffset = 0;
  2365. if(this.style.align === 'right')
  2366. {
  2367. alignOffset = maxLineWidth - lineWidths[i];
  2368. }
  2369. else if(this.style.align === 'center')
  2370. {
  2371. alignOffset = (maxLineWidth - lineWidths[i]) / 2;
  2372. }
  2373. lineAlignOffsets.push(alignOffset);
  2374. }
  2375. var lenChildren = this.children.length;
  2376. var lenChars = chars.length;
  2377. var tint = this.tint || 0xFFFFFF;
  2378. for(i = 0; i < lenChars; i++)
  2379. {
  2380. var c = i < lenChildren ? this.children[i] : this._pool.pop(); // get old child if have. if not - take from pool.
  2381. if (c) c.setTexture(chars[i].texture); // check if got one before.
  2382. else c = new PIXI.Sprite(chars[i].texture); // if no create new one.
  2383. c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale;
  2384. c.position.y = chars[i].position.y * scale;
  2385. c.scale.x = c.scale.y = scale;
  2386. c.tint = tint;
  2387. if (!c.parent) this.addChild(c);
  2388. }
  2389. // remove unnecessary children.
  2390. // and put their into the pool.
  2391. while(this.children.length > lenChars)
  2392. {
  2393. var child = this.getChildAt(this.children.length - 1);
  2394. this._pool.push(child);
  2395. this.removeChild(child);
  2396. }
  2397. /**
  2398. * [read-only] The width of the overall text, different from fontSize,
  2399. * which is defined in the style object
  2400. *
  2401. * @property textWidth
  2402. * @type Number
  2403. */
  2404. this.textWidth = maxLineWidth * scale;
  2405. /**
  2406. * [read-only] The height of the overall text, different from fontSize,
  2407. * which is defined in the style object
  2408. *
  2409. * @property textHeight
  2410. * @type Number
  2411. */
  2412. this.textHeight = (pos.y + data.lineHeight) * scale;
  2413. };
  2414. /**
  2415. * Updates the transform of this object
  2416. *
  2417. * @method updateTransform
  2418. * @private
  2419. */
  2420. PIXI.BitmapText.prototype.updateTransform = function()
  2421. {
  2422. if(this.dirty)
  2423. {
  2424. this.updateText();
  2425. this.dirty = false;
  2426. }
  2427. PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
  2428. };
  2429. PIXI.BitmapText.fonts = {};
  2430. /**
  2431. * @author Mat Groves http://matgroves.com/ @Doormat23
  2432. */
  2433. /**
  2434. * A Stage represents the root of the display tree. Everything connected to the stage is rendered
  2435. *
  2436. * @class Stage
  2437. * @extends DisplayObjectContainer
  2438. * @constructor
  2439. * @param backgroundColor {Number} the background color of the stage, you have to pass this in is in hex format
  2440. * like: 0xFFFFFF for white
  2441. *
  2442. * Creating a stage is a mandatory process when you use Pixi, which is as simple as this :
  2443. * var stage = new PIXI.Stage(0xFFFFFF);
  2444. * where the parameter given is the background colour of the stage, in hex
  2445. * you will use this stage instance to add your sprites to it and therefore to the renderer
  2446. * Here is how to add a sprite to the stage :
  2447. * stage.addChild(sprite);
  2448. */
  2449. PIXI.Stage = function(backgroundColor)
  2450. {
  2451. PIXI.DisplayObjectContainer.call( this );
  2452. /**
  2453. * [read-only] Current transform of the object based on world (parent) factors
  2454. *
  2455. * @property worldTransform
  2456. * @type Mat3
  2457. * @readOnly
  2458. * @private
  2459. */
  2460. this.worldTransform = new PIXI.Matrix();
  2461. /**
  2462. * Whether or not the stage is interactive
  2463. *
  2464. * @property interactive
  2465. * @type Boolean
  2466. */
  2467. this.interactive = true;
  2468. /**
  2469. * The interaction manage for this stage, manages all interactive activity on the stage
  2470. *
  2471. * @property interactive
  2472. * @type InteractionManager
  2473. */
  2474. this.interactionManager = new PIXI.InteractionManager(this);
  2475. /**
  2476. * Whether the stage is dirty and needs to have interactions updated
  2477. *
  2478. * @property dirty
  2479. * @type Boolean
  2480. * @private
  2481. */
  2482. this.dirty = true;
  2483. //the stage is its own stage
  2484. this.stage = this;
  2485. //optimize hit detection a bit
  2486. this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000);
  2487. this.setBackgroundColor(backgroundColor);
  2488. };
  2489. // constructor
  2490. PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
  2491. PIXI.Stage.prototype.constructor = PIXI.Stage;
  2492. /**
  2493. * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element.
  2494. * This is useful for when you have other DOM elements on top of the Canvas element.
  2495. *
  2496. * @method setInteractionDelegate
  2497. * @param domElement {DOMElement} This new domElement which will receive mouse/touch events
  2498. */
  2499. PIXI.Stage.prototype.setInteractionDelegate = function(domElement)
  2500. {
  2501. this.interactionManager.setTargetDomElement( domElement );
  2502. };
  2503. /*
  2504. * Updates the object transform for rendering
  2505. *
  2506. * @method updateTransform
  2507. * @private
  2508. */
  2509. PIXI.Stage.prototype.updateTransform = function()
  2510. {
  2511. this.worldAlpha = 1;
  2512. for(var i=0,j=this.children.length; i<j; i++)
  2513. {
  2514. this.children[i].updateTransform();
  2515. }
  2516. if(this.dirty)
  2517. {
  2518. this.dirty = false;
  2519. // update interactive!
  2520. this.interactionManager.dirty = true;
  2521. }
  2522. if(this.interactive)this.interactionManager.update();
  2523. };
  2524. /**
  2525. * Sets the background color for the stage
  2526. *
  2527. * @method setBackgroundColor
  2528. * @param backgroundColor {Number} the color of the background, easiest way to pass this in is in hex format
  2529. * like: 0xFFFFFF for white
  2530. */
  2531. PIXI.Stage.prototype.setBackgroundColor = function(backgroundColor)
  2532. {
  2533. this.backgroundColor = backgroundColor || 0x000000;
  2534. this.backgroundColorSplit = PIXI.hex2rgb(this.backgroundColor);
  2535. var hex = this.backgroundColor.toString(16);
  2536. hex = '000000'.substr(0, 6 - hex.length) + hex;
  2537. this.backgroundColorString = '#' + hex;
  2538. };
  2539. /**
  2540. * This will return the point containing global coords of the mouse.
  2541. *
  2542. * @method getMousePosition
  2543. * @return {Point} The point containing the coords of the global InteractionData position.
  2544. */
  2545. PIXI.Stage.prototype.getMousePosition = function()
  2546. {
  2547. return this.interactionManager.mouse.global;
  2548. };
  2549. /**
  2550. * @author Mat Groves http://matgroves.com/ @Doormat23
  2551. */
  2552. // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  2553. // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
  2554. // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
  2555. // MIT license
  2556. /**
  2557. * A polyfill for requestAnimationFrame
  2558. * You can actually use both requestAnimationFrame and requestAnimFrame,
  2559. * you will still benefit from the polyfill
  2560. *
  2561. * @method requestAnimationFrame
  2562. */
  2563. /**
  2564. * A polyfill for cancelAnimationFrame
  2565. *
  2566. * @method cancelAnimationFrame
  2567. */
  2568. var lastTime = 0;
  2569. var vendors = ['ms', 'moz', 'webkit', 'o'];
  2570. for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  2571. window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
  2572. window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
  2573. window[vendors[x] + 'CancelRequestAnimationFrame'];
  2574. }
  2575. if (!window.requestAnimationFrame) {
  2576. window.requestAnimationFrame = function(callback) {
  2577. var currTime = new Date().getTime();
  2578. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  2579. var id = window.setTimeout(function() { callback(currTime + timeToCall); },
  2580. timeToCall);
  2581. lastTime = currTime + timeToCall;
  2582. return id;
  2583. };
  2584. }
  2585. if (!window.cancelAnimationFrame) {
  2586. window.cancelAnimationFrame = function(id) {
  2587. clearTimeout(id);
  2588. };
  2589. }
  2590. window.requestAnimFrame = window.requestAnimationFrame;
  2591. /**
  2592. * Converts a hex color number to an [R, G, B] array
  2593. *
  2594. * @method hex2rgb
  2595. * @param hex {Number}
  2596. */
  2597. PIXI.hex2rgb = function(hex) {
  2598. return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255];
  2599. };
  2600. /**
  2601. * Converts a color as an [R, G, B] array to a hex number
  2602. *
  2603. * @method rgb2hex
  2604. * @param rgb {Array}
  2605. */
  2606. PIXI.rgb2hex = function(rgb) {
  2607. return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255);
  2608. };
  2609. /**
  2610. * A polyfill for Function.prototype.bind
  2611. *
  2612. * @method bind
  2613. */
  2614. if (typeof Function.prototype.bind !== 'function') {
  2615. Function.prototype.bind = (function () {
  2616. var slice = Array.prototype.slice;
  2617. return function (thisArg) {
  2618. var target = this, boundArgs = slice.call(arguments, 1);
  2619. if (typeof target !== 'function') throw new TypeError();
  2620. function bound() {
  2621. var args = boundArgs.concat(slice.call(arguments));
  2622. target.apply(this instanceof bound ? this : thisArg, args);
  2623. }
  2624. bound.prototype = (function F(proto) {
  2625. if (proto) F.prototype = proto;
  2626. if (!(this instanceof F)) return new F();
  2627. })(target.prototype);
  2628. return bound;
  2629. };
  2630. })();
  2631. }
  2632. /**
  2633. * A wrapper for ajax requests to be handled cross browser
  2634. *
  2635. * @class AjaxRequest
  2636. * @constructor
  2637. */
  2638. PIXI.AjaxRequest = function()
  2639. {
  2640. var activexmodes = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']; //activeX versions to check for in IE
  2641. if (window.ActiveXObject)
  2642. { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
  2643. for (var i=0; i<activexmodes.length; i++)
  2644. {
  2645. try{
  2646. return new window.ActiveXObject(activexmodes[i]);
  2647. }
  2648. catch(e) {
  2649. //suppress error
  2650. }
  2651. }
  2652. }
  2653. else if (window.XMLHttpRequest) // if Mozilla, Safari etc
  2654. {
  2655. return new window.XMLHttpRequest();
  2656. }
  2657. else
  2658. {
  2659. return false;
  2660. }
  2661. };
  2662. /*
  2663. PIXI.packColorRGBA = function(r, g, b, a)//r, g, b, a)
  2664. {
  2665. // console.log(r, b, c, d)
  2666. return (Math.floor((r)*63) << 18) | (Math.floor((g)*63) << 12) | (Math.floor((b)*63) << 6);// | (Math.floor((a)*63))
  2667. // i = i | (Math.floor((a)*63));
  2668. // return i;
  2669. // var r = (i / 262144.0 ) / 64;
  2670. // var g = (i / 4096.0)%64 / 64;
  2671. // var b = (i / 64.0)%64 / 64;
  2672. // var a = (i)%64 / 64;
  2673. // console.log(r, g, b, a);
  2674. // return i;
  2675. };
  2676. */
  2677. /*
  2678. PIXI.packColorRGB = function(r, g, b)//r, g, b, a)
  2679. {
  2680. return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255));
  2681. };
  2682. PIXI.unpackColorRGB = function(r, g, b)//r, g, b, a)
  2683. {
  2684. return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255));
  2685. };
  2686. */
  2687. /**
  2688. * Checks whether the Canvas BlendModes are supported by the current browser
  2689. *
  2690. * @method canUseNewCanvasBlendModes
  2691. * @return {Boolean} whether they are supported
  2692. */
  2693. PIXI.canUseNewCanvasBlendModes = function()
  2694. {
  2695. var canvas = document.createElement('canvas');
  2696. canvas.width = 1;
  2697. canvas.height = 1;
  2698. var context = canvas.getContext('2d');
  2699. context.fillStyle = '#000';
  2700. context.fillRect(0,0,1,1);
  2701. context.globalCompositeOperation = 'multiply';
  2702. context.fillStyle = '#fff';
  2703. context.fillRect(0,0,1,1);
  2704. return context.getImageData(0,0,1,1).data[0] === 0;
  2705. };
  2706. /**
  2707. * Given a number, this function returns the closest number that is a power of two
  2708. * this function is taken from Starling Framework as its pretty neat ;)
  2709. *
  2710. * @method getNextPowerOfTwo
  2711. * @param number {Number}
  2712. * @return {Number} the closest number that is a power of two
  2713. */
  2714. PIXI.getNextPowerOfTwo = function(number)
  2715. {
  2716. if (number > 0 && (number & (number - 1)) === 0) // see: http://goo.gl/D9kPj
  2717. return number;
  2718. else
  2719. {
  2720. var result = 1;
  2721. while (result < number) result <<= 1;
  2722. return result;
  2723. }
  2724. };
  2725. /**
  2726. * @author Mat Groves http://matgroves.com/ @Doormat23
  2727. */
  2728. /**
  2729. * https://github.com/mrdoob/eventtarget.js/
  2730. * THankS mr DOob!
  2731. */
  2732. /**
  2733. * Adds event emitter functionality to a class
  2734. *
  2735. * @class EventTarget
  2736. * @example
  2737. * function MyEmitter() {
  2738. * PIXI.EventTarget.call(this); //mixes in event target stuff
  2739. * }
  2740. *
  2741. * var em = new MyEmitter();
  2742. * em.emit({ type: 'eventName', data: 'some data' });
  2743. */
  2744. PIXI.EventTarget = function () {
  2745. /**
  2746. * Holds all the listeners
  2747. *
  2748. * @property listeners
  2749. * @type Object
  2750. */
  2751. var listeners = {};
  2752. /**
  2753. * Adds a listener for a specific event
  2754. *
  2755. * @method addEventListener
  2756. * @param type {string} A string representing the event type to listen for.
  2757. * @param listener {function} The callback function that will be fired when the event occurs
  2758. */
  2759. this.addEventListener = this.on = function ( type, listener ) {
  2760. if ( listeners[ type ] === undefined ) {
  2761. listeners[ type ] = [];
  2762. }
  2763. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  2764. listeners[ type ].push( listener );
  2765. }
  2766. };
  2767. /**
  2768. * Fires the event, ie pretends that the event has happened
  2769. *
  2770. * @method dispatchEvent
  2771. * @param event {Event} the event object
  2772. */
  2773. this.dispatchEvent = this.emit = function ( event ) {
  2774. if ( !listeners[ event.type ] || !listeners[ event.type ].length ) {
  2775. return;
  2776. }
  2777. for(var i = 0, l = listeners[ event.type ].length; i < l; i++) {
  2778. listeners[ event.type ][ i ]( event );
  2779. }
  2780. };
  2781. /**
  2782. * Removes the specified listener that was assigned to the specified event type
  2783. *
  2784. * @method removeEventListener
  2785. * @param type {string} A string representing the event type which will have its listener removed
  2786. * @param listener {function} The callback function that was be fired when the event occured
  2787. */
  2788. this.removeEventListener = this.off = function ( type, listener ) {
  2789. var index = listeners[ type ].indexOf( listener );
  2790. if ( index !== - 1 ) {
  2791. listeners[ type ].splice( index, 1 );
  2792. }
  2793. };
  2794. /**
  2795. * Removes all the listeners that were active for the specified event type
  2796. *
  2797. * @method removeAllEventListeners
  2798. * @param type {string} A string representing the event type which will have all its listeners removed
  2799. */
  2800. this.removeAllEventListeners = function( type ) {
  2801. var a = listeners[type];
  2802. if (a)
  2803. a.length = 0;
  2804. };
  2805. };
  2806. /*
  2807. PolyK library
  2808. url: http://polyk.ivank.net
  2809. Released under MIT licence.
  2810. Copyright (c) 2012 Ivan Kuckir
  2811. Permission is hereby granted, free of charge, to any person
  2812. obtaining a copy of this software and associated documentation
  2813. files (the "Software"), to deal in the Software without
  2814. restriction, including without limitation the rights to use,
  2815. copy, modify, merge, publish, distribute, sublicense, and/or sell
  2816. copies of the Software, and to permit persons to whom the
  2817. Software is furnished to do so, subject to the following
  2818. conditions:
  2819. The above copyright notice and this permission notice shall be
  2820. included in all copies or substantial portions of the Software.
  2821. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  2822. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  2823. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  2824. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  2825. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  2826. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2827. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  2828. OTHER DEALINGS IN THE SOFTWARE.
  2829. This is an amazing lib!
  2830. slightly modified by Mat Groves (matgroves.com);
  2831. */
  2832. /**
  2833. * Based on the Polyk library http://polyk.ivank.net released under MIT licence.
  2834. * This is an amazing lib!
  2835. * slightly modified by Mat Groves (matgroves.com);
  2836. * @class PolyK
  2837. *
  2838. */
  2839. PIXI.PolyK = {};
  2840. /**
  2841. * Triangulates shapes for webGL graphic fills
  2842. *
  2843. * @method Triangulate
  2844. *
  2845. */
  2846. PIXI.PolyK.Triangulate = function(p)
  2847. {
  2848. var sign = true;
  2849. var n = p.length >> 1;
  2850. if(n < 3) return [];
  2851. var tgs = [];
  2852. var avl = [];
  2853. for(var i = 0; i < n; i++) avl.push(i);
  2854. i = 0;
  2855. var al = n;
  2856. while(al > 3)
  2857. {
  2858. var i0 = avl[(i+0)%al];
  2859. var i1 = avl[(i+1)%al];
  2860. var i2 = avl[(i+2)%al];
  2861. var ax = p[2*i0], ay = p[2*i0+1];
  2862. var bx = p[2*i1], by = p[2*i1+1];
  2863. var cx = p[2*i2], cy = p[2*i2+1];
  2864. var earFound = false;
  2865. if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign))
  2866. {
  2867. earFound = true;
  2868. for(var j = 0; j < al; j++)
  2869. {
  2870. var vi = avl[j];
  2871. if(vi === i0 || vi === i1 || vi === i2) continue;
  2872. if(PIXI.PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) {
  2873. earFound = false;
  2874. break;
  2875. }
  2876. }
  2877. }
  2878. if(earFound)
  2879. {
  2880. tgs.push(i0, i1, i2);
  2881. avl.splice((i+1)%al, 1);
  2882. al--;
  2883. i = 0;
  2884. }
  2885. else if(i++ > 3*al)
  2886. {
  2887. // need to flip flip reverse it!
  2888. // reset!
  2889. if(sign)
  2890. {
  2891. tgs = [];
  2892. avl = [];
  2893. for(i = 0; i < n; i++) avl.push(i);
  2894. i = 0;
  2895. al = n;
  2896. sign = false;
  2897. }
  2898. else
  2899. {
  2900. window.console.log("PIXI Warning: shape too complex to fill");
  2901. return [];
  2902. }
  2903. }
  2904. }
  2905. tgs.push(avl[0], avl[1], avl[2]);
  2906. return tgs;
  2907. };
  2908. /**
  2909. * Checks whether a point is within a triangle
  2910. *
  2911. * @method _PointInTriangle
  2912. * @param px {Number} x coordinate of the point to test
  2913. * @param py {Number} y coordinate of the point to test
  2914. * @param ax {Number} x coordinate of the a point of the triangle
  2915. * @param ay {Number} y coordinate of the a point of the triangle
  2916. * @param bx {Number} x coordinate of the b point of the triangle
  2917. * @param by {Number} y coordinate of the b point of the triangle
  2918. * @param cx {Number} x coordinate of the c point of the triangle
  2919. * @param cy {Number} y coordinate of the c point of the triangle
  2920. * @private
  2921. */
  2922. PIXI.PolyK._PointInTriangle = function(px, py, ax, ay, bx, by, cx, cy)
  2923. {
  2924. var v0x = cx-ax;
  2925. var v0y = cy-ay;
  2926. var v1x = bx-ax;
  2927. var v1y = by-ay;
  2928. var v2x = px-ax;
  2929. var v2y = py-ay;
  2930. var dot00 = v0x*v0x+v0y*v0y;
  2931. var dot01 = v0x*v1x+v0y*v1y;
  2932. var dot02 = v0x*v2x+v0y*v2y;
  2933. var dot11 = v1x*v1x+v1y*v1y;
  2934. var dot12 = v1x*v2x+v1y*v2y;
  2935. var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
  2936. var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  2937. var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  2938. // Check if point is in triangle
  2939. return (u >= 0) && (v >= 0) && (u + v < 1);
  2940. };
  2941. /**
  2942. * Checks whether a shape is convex
  2943. *
  2944. * @method _convex
  2945. *
  2946. * @private
  2947. */
  2948. PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign)
  2949. {
  2950. return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) === sign;
  2951. };
  2952. /**
  2953. * @author Mat Groves http://matgroves.com/ @Doormat23
  2954. */
  2955. // TODO Alvin and Mat
  2956. // Should we eventually create a Utils class ?
  2957. // Or just move this file to the pixi.js file ?
  2958. PIXI.initDefaultShaders = function()
  2959. {
  2960. // PIXI.stripShader = new PIXI.StripShader();
  2961. // PIXI.stripShader.init();
  2962. };
  2963. PIXI.CompileVertexShader = function(gl, shaderSrc)
  2964. {
  2965. return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER);
  2966. };
  2967. PIXI.CompileFragmentShader = function(gl, shaderSrc)
  2968. {
  2969. return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER);
  2970. };
  2971. PIXI._CompileShader = function(gl, shaderSrc, shaderType)
  2972. {
  2973. var src = shaderSrc.join("\n");
  2974. var shader = gl.createShader(shaderType);
  2975. gl.shaderSource(shader, src);
  2976. gl.compileShader(shader);
  2977. if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  2978. window.console.log(gl.getShaderInfoLog(shader));
  2979. return null;
  2980. }
  2981. return shader;
  2982. };
  2983. PIXI.compileProgram = function(gl, vertexSrc, fragmentSrc)
  2984. {
  2985. var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc);
  2986. var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc);
  2987. var shaderProgram = gl.createProgram();
  2988. gl.attachShader(shaderProgram, vertexShader);
  2989. gl.attachShader(shaderProgram, fragmentShader);
  2990. gl.linkProgram(shaderProgram);
  2991. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
  2992. window.console.log("Could not initialise shaders");
  2993. }
  2994. return shaderProgram;
  2995. };
  2996. /**
  2997. * @author Mat Groves http://matgroves.com/ @Doormat23
  2998. * @author Richard Davey http://www.photonstorm.com @photonstorm
  2999. */
  3000. /**
  3001. * @class PixiShader
  3002. * @constructor
  3003. */
  3004. PIXI.PixiShader = function(gl)
  3005. {
  3006. /**
  3007. * @property gl
  3008. * @type WebGLContext
  3009. */
  3010. this.gl = gl;
  3011. /**
  3012. * @property {any} program - The WebGL program.
  3013. */
  3014. this.program = null;
  3015. /**
  3016. * @property {array} fragmentSrc - The fragment shader.
  3017. */
  3018. this.fragmentSrc = [
  3019. 'precision lowp float;',
  3020. 'varying vec2 vTextureCoord;',
  3021. 'varying vec4 vColor;',
  3022. 'uniform sampler2D uSampler;',
  3023. 'void main(void) {',
  3024. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
  3025. '}'
  3026. ];
  3027. /**
  3028. * @property {number} textureCount - A local texture counter for multi-texture shaders.
  3029. */
  3030. this.textureCount = 0;
  3031. this.attributes = [];
  3032. this.init();
  3033. };
  3034. /**
  3035. * Initialises the shader
  3036. * @method init
  3037. *
  3038. */
  3039. PIXI.PixiShader.prototype.init = function()
  3040. {
  3041. var gl = this.gl;
  3042. var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc);
  3043. gl.useProgram(program);
  3044. // get and store the uniforms for the shader
  3045. this.uSampler = gl.getUniformLocation(program, 'uSampler');
  3046. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  3047. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  3048. this.dimensions = gl.getUniformLocation(program, 'dimensions');
  3049. // get and store the attributes
  3050. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  3051. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  3052. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  3053. // Begin worst hack eva //
  3054. // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
  3055. // maybe its something to do with the current state of the gl context.
  3056. // 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
  3057. // If theres any webGL people that know why could happen please help :)
  3058. if(this.colorAttribute === -1)
  3059. {
  3060. this.colorAttribute = 2;
  3061. }
  3062. this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute];
  3063. // End worst hack eva //
  3064. // add those custom shaders!
  3065. for (var key in this.uniforms)
  3066. {
  3067. // get the uniform locations..
  3068. this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key);
  3069. }
  3070. this.initUniforms();
  3071. this.program = program;
  3072. };
  3073. /**
  3074. * Initialises the shader uniform values.
  3075. * Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/
  3076. * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
  3077. *
  3078. * @method initUniforms
  3079. */
  3080. PIXI.PixiShader.prototype.initUniforms = function()
  3081. {
  3082. this.textureCount = 1;
  3083. var gl = this.gl;
  3084. var uniform;
  3085. for (var key in this.uniforms)
  3086. {
  3087. uniform = this.uniforms[key];
  3088. var type = uniform.type;
  3089. if (type === 'sampler2D')
  3090. {
  3091. uniform._init = false;
  3092. if (uniform.value !== null)
  3093. {
  3094. this.initSampler2D(uniform);
  3095. }
  3096. }
  3097. else if (type === 'mat2' || type === 'mat3' || type === 'mat4')
  3098. {
  3099. // These require special handling
  3100. uniform.glMatrix = true;
  3101. uniform.glValueLength = 1;
  3102. if (type === 'mat2')
  3103. {
  3104. uniform.glFunc = gl.uniformMatrix2fv;
  3105. }
  3106. else if (type === 'mat3')
  3107. {
  3108. uniform.glFunc = gl.uniformMatrix3fv;
  3109. }
  3110. else if (type === 'mat4')
  3111. {
  3112. uniform.glFunc = gl.uniformMatrix4fv;
  3113. }
  3114. }
  3115. else
  3116. {
  3117. // GL function reference
  3118. uniform.glFunc = gl['uniform' + type];
  3119. if (type === '2f' || type === '2i')
  3120. {
  3121. uniform.glValueLength = 2;
  3122. }
  3123. else if (type === '3f' || type === '3i')
  3124. {
  3125. uniform.glValueLength = 3;
  3126. }
  3127. else if (type === '4f' || type === '4i')
  3128. {
  3129. uniform.glValueLength = 4;
  3130. }
  3131. else
  3132. {
  3133. uniform.glValueLength = 1;
  3134. }
  3135. }
  3136. }
  3137. };
  3138. /**
  3139. * Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded)
  3140. *
  3141. * @method initSampler2D
  3142. */
  3143. PIXI.PixiShader.prototype.initSampler2D = function(uniform)
  3144. {
  3145. if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded)
  3146. {
  3147. return;
  3148. }
  3149. var gl = this.gl;
  3150. gl.activeTexture(gl['TEXTURE' + this.textureCount]);
  3151. gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id]);
  3152. // Extended texture data
  3153. if (uniform.textureData)
  3154. {
  3155. var data = uniform.textureData;
  3156. // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D);
  3157. // GLTextureLinear = mag/min linear, wrap clamp
  3158. // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat
  3159. // GLTextureNearest = mag/min nearest, wrap clamp
  3160. // AudioTexture = whatever + luminance + width 512, height 2, border 0
  3161. // KeyTexture = whatever + luminance + width 256, height 2, border 0
  3162. // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
  3163. // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT
  3164. var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR;
  3165. var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR;
  3166. var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE;
  3167. var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE;
  3168. var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA;
  3169. if (data.repeat)
  3170. {
  3171. wrapS = gl.REPEAT;
  3172. wrapT = gl.REPEAT;
  3173. }
  3174. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY);
  3175. if (data.width)
  3176. {
  3177. var width = (data.width) ? data.width : 512;
  3178. var height = (data.height) ? data.height : 2;
  3179. var border = (data.border) ? data.border : 0;
  3180. // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
  3181. gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null);
  3182. }
  3183. else
  3184. {
  3185. // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels);
  3186. gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source);
  3187. }
  3188. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
  3189. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
  3190. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
  3191. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
  3192. }
  3193. gl.uniform1i(uniform.uniformLocation, this.textureCount);
  3194. uniform._init = true;
  3195. this.textureCount++;
  3196. };
  3197. /**
  3198. * Updates the shader uniform values.
  3199. *
  3200. * @method syncUniforms
  3201. */
  3202. PIXI.PixiShader.prototype.syncUniforms = function()
  3203. {
  3204. this.textureCount = 1;
  3205. var uniform;
  3206. var gl = this.gl;
  3207. // This would probably be faster in an array and it would guarantee key order
  3208. for (var key in this.uniforms)
  3209. {
  3210. uniform = this.uniforms[key];
  3211. if (uniform.glValueLength === 1)
  3212. {
  3213. if (uniform.glMatrix === true)
  3214. {
  3215. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.transpose, uniform.value);
  3216. }
  3217. else
  3218. {
  3219. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value);
  3220. }
  3221. }
  3222. else if (uniform.glValueLength === 2)
  3223. {
  3224. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y);
  3225. }
  3226. else if (uniform.glValueLength === 3)
  3227. {
  3228. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z);
  3229. }
  3230. else if (uniform.glValueLength === 4)
  3231. {
  3232. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w);
  3233. }
  3234. else if (uniform.type === 'sampler2D')
  3235. {
  3236. if (uniform._init)
  3237. {
  3238. gl.activeTexture(gl['TEXTURE' + this.textureCount]);
  3239. gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture( uniform.value.baseTexture, gl));
  3240. gl.uniform1i(uniform.uniformLocation, this.textureCount);
  3241. this.textureCount++;
  3242. }
  3243. else
  3244. {
  3245. this.initSampler2D(uniform);
  3246. }
  3247. }
  3248. }
  3249. };
  3250. /**
  3251. * Destroys the shader
  3252. * @method destroy
  3253. */
  3254. PIXI.PixiShader.prototype.destroy = function()
  3255. {
  3256. this.gl.deleteProgram( this.program );
  3257. this.uniforms = null;
  3258. this.gl = null;
  3259. this.attributes = null;
  3260. };
  3261. /**
  3262. * The Default Vertex shader source
  3263. * @property defaultVertexSrc
  3264. * @type String
  3265. */
  3266. PIXI.PixiShader.defaultVertexSrc = [
  3267. 'attribute vec2 aVertexPosition;',
  3268. 'attribute vec2 aTextureCoord;',
  3269. 'attribute vec2 aColor;',
  3270. 'uniform vec2 projectionVector;',
  3271. 'uniform vec2 offsetVector;',
  3272. 'varying vec2 vTextureCoord;',
  3273. 'varying vec4 vColor;',
  3274. 'const vec2 center = vec2(-1.0, 1.0);',
  3275. 'void main(void) {',
  3276. ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);',
  3277. ' vTextureCoord = aTextureCoord;',
  3278. ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
  3279. ' vColor = vec4(color * aColor.x, aColor.x);',
  3280. '}'
  3281. ];
  3282. /**
  3283. * @author Mat Groves http://matgroves.com/ @Doormat23
  3284. * @author Richard Davey http://www.photonstorm.com @photonstorm
  3285. */
  3286. /**
  3287. * @class PixiFastShader
  3288. * @constructor
  3289. * @param gl {WebGLContext} the current WebGL drawing context
  3290. */
  3291. PIXI.PixiFastShader = function(gl)
  3292. {
  3293. /**
  3294. * @property gl
  3295. * @type WebGLContext
  3296. */
  3297. this.gl = gl;
  3298. /**
  3299. * @property {any} program - The WebGL program.
  3300. */
  3301. this.program = null;
  3302. /**
  3303. * @property {array} fragmentSrc - The fragment shader.
  3304. */
  3305. this.fragmentSrc = [
  3306. 'precision lowp float;',
  3307. 'varying vec2 vTextureCoord;',
  3308. 'varying float vColor;',
  3309. 'uniform sampler2D uSampler;',
  3310. 'void main(void) {',
  3311. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
  3312. '}'
  3313. ];
  3314. /**
  3315. * @property {array} vertexSrc - The vertex shader
  3316. */
  3317. this.vertexSrc = [
  3318. 'attribute vec2 aVertexPosition;',
  3319. 'attribute vec2 aPositionCoord;',
  3320. 'attribute vec2 aScale;',
  3321. 'attribute float aRotation;',
  3322. 'attribute vec2 aTextureCoord;',
  3323. 'attribute float aColor;',
  3324. 'uniform vec2 projectionVector;',
  3325. 'uniform vec2 offsetVector;',
  3326. 'uniform mat3 uMatrix;',
  3327. 'varying vec2 vTextureCoord;',
  3328. 'varying float vColor;',
  3329. 'const vec2 center = vec2(-1.0, 1.0);',
  3330. 'void main(void) {',
  3331. ' vec2 v;',
  3332. ' vec2 sv = aVertexPosition * aScale;',
  3333. ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);',
  3334. ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);',
  3335. ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;',
  3336. ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);',
  3337. ' vTextureCoord = aTextureCoord;',
  3338. // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
  3339. ' vColor = aColor;',
  3340. '}'
  3341. ];
  3342. /**
  3343. * @property {number} textureCount - A local texture counter for multi-texture shaders.
  3344. */
  3345. this.textureCount = 0;
  3346. this.init();
  3347. };
  3348. /**
  3349. * Initialises the shader
  3350. * @method init
  3351. *
  3352. */
  3353. PIXI.PixiFastShader.prototype.init = function()
  3354. {
  3355. var gl = this.gl;
  3356. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  3357. gl.useProgram(program);
  3358. // get and store the uniforms for the shader
  3359. this.uSampler = gl.getUniformLocation(program, 'uSampler');
  3360. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  3361. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  3362. this.dimensions = gl.getUniformLocation(program, 'dimensions');
  3363. this.uMatrix = gl.getUniformLocation(program, 'uMatrix');
  3364. // get and store the attributes
  3365. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  3366. this.aPositionCoord = gl.getAttribLocation(program, 'aPositionCoord');
  3367. this.aScale = gl.getAttribLocation(program, 'aScale');
  3368. this.aRotation = gl.getAttribLocation(program, 'aRotation');
  3369. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  3370. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  3371. // Begin worst hack eva //
  3372. // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
  3373. // maybe its somthing to do with the current state of the gl context.
  3374. // 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
  3375. // If theres any webGL people that know why could happen please help :)
  3376. if(this.colorAttribute === -1)
  3377. {
  3378. this.colorAttribute = 2;
  3379. }
  3380. this.attributes = [this.aVertexPosition, this.aPositionCoord, this.aScale, this.aRotation, this.aTextureCoord, this.colorAttribute];
  3381. // End worst hack eva //
  3382. this.program = program;
  3383. };
  3384. /**
  3385. * Destroys the shader
  3386. * @method destroy
  3387. *
  3388. */
  3389. PIXI.PixiFastShader.prototype.destroy = function()
  3390. {
  3391. this.gl.deleteProgram( this.program );
  3392. this.uniforms = null;
  3393. this.gl = null;
  3394. this.attributes = null;
  3395. };
  3396. /**
  3397. * @author Mat Groves http://matgroves.com/ @Doormat23
  3398. */
  3399. PIXI.StripShader = function()
  3400. {
  3401. /**
  3402. * @property {any} program - The WebGL program.
  3403. */
  3404. this.program = null;
  3405. /**
  3406. * @property {array} fragmentSrc - The fragment shader.
  3407. */
  3408. this.fragmentSrc = [
  3409. 'precision mediump float;',
  3410. 'varying vec2 vTextureCoord;',
  3411. 'varying float vColor;',
  3412. 'uniform float alpha;',
  3413. 'uniform sampler2D uSampler;',
  3414. 'void main(void) {',
  3415. ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));',
  3416. ' gl_FragColor = gl_FragColor * alpha;',
  3417. '}'
  3418. ];
  3419. /**
  3420. * @property {array} fragmentSrc - The fragment shader.
  3421. */
  3422. this.vertexSrc = [
  3423. 'attribute vec2 aVertexPosition;',
  3424. 'attribute vec2 aTextureCoord;',
  3425. 'attribute float aColor;',
  3426. 'uniform mat3 translationMatrix;',
  3427. 'uniform vec2 projectionVector;',
  3428. 'varying vec2 vTextureCoord;',
  3429. 'uniform vec2 offsetVector;',
  3430. 'varying float vColor;',
  3431. 'void main(void) {',
  3432. ' vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);',
  3433. ' v -= offsetVector.xyx;',
  3434. ' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);',
  3435. ' vTextureCoord = aTextureCoord;',
  3436. ' vColor = aColor;',
  3437. '}'
  3438. ];
  3439. };
  3440. /**
  3441. * Initialises the shader
  3442. * @method init
  3443. *
  3444. */
  3445. PIXI.StripShader.prototype.init = function()
  3446. {
  3447. var gl = PIXI.gl;
  3448. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  3449. gl.useProgram(program);
  3450. // get and store the uniforms for the shader
  3451. this.uSampler = gl.getUniformLocation(program, 'uSampler');
  3452. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  3453. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  3454. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  3455. //this.dimensions = gl.getUniformLocation(this.program, 'dimensions');
  3456. // get and store the attributes
  3457. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  3458. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  3459. this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
  3460. this.alpha = gl.getUniformLocation(program, 'alpha');
  3461. this.program = program;
  3462. };
  3463. /**
  3464. * @author Mat Groves http://matgroves.com/ @Doormat23
  3465. */
  3466. /**
  3467. * @class PrimitiveShader
  3468. * @constructor
  3469. * @param gl {WebGLContext} the current WebGL drawing context
  3470. */
  3471. PIXI.PrimitiveShader = function(gl)
  3472. {
  3473. /**
  3474. * @property gl
  3475. * @type WebGLContext
  3476. */
  3477. this.gl = gl;
  3478. /**
  3479. * @property {any} program - The WebGL program.
  3480. */
  3481. this.program = null;
  3482. /**
  3483. * @property fragmentSrc
  3484. * @type Array
  3485. */
  3486. this.fragmentSrc = [
  3487. 'precision mediump float;',
  3488. 'varying vec4 vColor;',
  3489. 'void main(void) {',
  3490. ' gl_FragColor = vColor;',
  3491. '}'
  3492. ];
  3493. /**
  3494. * @property vertexSrc
  3495. * @type Array
  3496. */
  3497. this.vertexSrc = [
  3498. 'attribute vec2 aVertexPosition;',
  3499. 'attribute vec4 aColor;',
  3500. 'uniform mat3 translationMatrix;',
  3501. 'uniform vec2 projectionVector;',
  3502. 'uniform vec2 offsetVector;',
  3503. 'uniform float alpha;',
  3504. 'uniform vec3 tint;',
  3505. 'varying vec4 vColor;',
  3506. 'void main(void) {',
  3507. ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);',
  3508. ' v -= offsetVector.xyx;',
  3509. ' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);',
  3510. ' vColor = aColor * vec4(tint * alpha, alpha);',
  3511. '}'
  3512. ];
  3513. this.init();
  3514. };
  3515. /**
  3516. * Initialises the shader
  3517. * @method init
  3518. *
  3519. */
  3520. PIXI.PrimitiveShader.prototype.init = function()
  3521. {
  3522. var gl = this.gl;
  3523. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  3524. gl.useProgram(program);
  3525. // get and store the uniforms for the shader
  3526. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  3527. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  3528. this.tintColor = gl.getUniformLocation(program, 'tint');
  3529. // get and store the attributes
  3530. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  3531. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  3532. this.attributes = [this.aVertexPosition, this.colorAttribute];
  3533. this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
  3534. this.alpha = gl.getUniformLocation(program, 'alpha');
  3535. this.program = program;
  3536. };
  3537. /**
  3538. * Destroys the shader
  3539. * @method destroy
  3540. *
  3541. */
  3542. PIXI.PrimitiveShader.prototype.destroy = function()
  3543. {
  3544. this.gl.deleteProgram( this.program );
  3545. this.uniforms = null;
  3546. this.gl = null;
  3547. this.attribute = null;
  3548. };
  3549. /**
  3550. * @author Mat Groves http://matgroves.com/ @Doormat23
  3551. */
  3552. /**
  3553. * A set of functions used by the webGL renderer to draw the primitive graphics data
  3554. *
  3555. * @class WebGLGraphics
  3556. * @private
  3557. * @static
  3558. */
  3559. PIXI.WebGLGraphics = function()
  3560. {
  3561. };
  3562. /**
  3563. * Renders the graphics object
  3564. *
  3565. * @static
  3566. * @private
  3567. * @method renderGraphics
  3568. * @param graphics {Graphics}
  3569. * @param renderSession {Object}
  3570. */
  3571. PIXI.WebGLGraphics.renderGraphics = function(graphics, renderSession)//projection, offset)
  3572. {
  3573. var gl = renderSession.gl;
  3574. var projection = renderSession.projection,
  3575. offset = renderSession.offset,
  3576. shader = renderSession.shaderManager.primitiveShader;
  3577. if(!graphics._webGL[gl.id])graphics._webGL[gl.id] = {points:[], indices:[], lastIndex:0,
  3578. buffer:gl.createBuffer(),
  3579. indexBuffer:gl.createBuffer()};
  3580. var webGL = graphics._webGL[gl.id];
  3581. if(graphics.dirty)
  3582. {
  3583. graphics.dirty = false;
  3584. if(graphics.clearDirty)
  3585. {
  3586. graphics.clearDirty = false;
  3587. webGL.lastIndex = 0;
  3588. webGL.points = [];
  3589. webGL.indices = [];
  3590. }
  3591. PIXI.WebGLGraphics.updateGraphics(graphics, gl);
  3592. }
  3593. renderSession.shaderManager.activatePrimitiveShader();
  3594. // This could be speeded up for sure!
  3595. // set the matrix transform
  3596. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  3597. gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true));
  3598. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  3599. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  3600. gl.uniform3fv(shader.tintColor, PIXI.hex2rgb(graphics.tint));
  3601. gl.uniform1f(shader.alpha, graphics.worldAlpha);
  3602. gl.bindBuffer(gl.ARRAY_BUFFER, webGL.buffer);
  3603. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0);
  3604. gl.vertexAttribPointer(shader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4);
  3605. // set the index buffer!
  3606. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGL.indexBuffer);
  3607. gl.drawElements(gl.TRIANGLE_STRIP, webGL.indices.length, gl.UNSIGNED_SHORT, 0 );
  3608. renderSession.shaderManager.deactivatePrimitiveShader();
  3609. // return to default shader...
  3610. // PIXI.activateShader(PIXI.defaultShader);
  3611. };
  3612. /**
  3613. * Updates the graphics object
  3614. *
  3615. * @static
  3616. * @private
  3617. * @method updateGraphics
  3618. * @param graphicsData {Graphics} The graphics object to update
  3619. * @param gl {WebGLContext} the current WebGL drawing context
  3620. */
  3621. PIXI.WebGLGraphics.updateGraphics = function(graphics, gl)
  3622. {
  3623. var webGL = graphics._webGL[gl.id];
  3624. for (var i = webGL.lastIndex; i < graphics.graphicsData.length; i++)
  3625. {
  3626. var data = graphics.graphicsData[i];
  3627. if(data.type === PIXI.Graphics.POLY)
  3628. {
  3629. if(data.fill)
  3630. {
  3631. if(data.points.length>3)
  3632. PIXI.WebGLGraphics.buildPoly(data, webGL);
  3633. }
  3634. if(data.lineWidth > 0)
  3635. {
  3636. PIXI.WebGLGraphics.buildLine(data, webGL);
  3637. }
  3638. }
  3639. else if(data.type === PIXI.Graphics.RECT)
  3640. {
  3641. PIXI.WebGLGraphics.buildRectangle(data, webGL);
  3642. }
  3643. else if(data.type === PIXI.Graphics.CIRC || data.type === PIXI.Graphics.ELIP)
  3644. {
  3645. PIXI.WebGLGraphics.buildCircle(data, webGL);
  3646. }
  3647. }
  3648. webGL.lastIndex = graphics.graphicsData.length;
  3649. webGL.glPoints = new Float32Array(webGL.points);
  3650. gl.bindBuffer(gl.ARRAY_BUFFER, webGL.buffer);
  3651. gl.bufferData(gl.ARRAY_BUFFER, webGL.glPoints, gl.STATIC_DRAW);
  3652. webGL.glIndicies = new Uint16Array(webGL.indices);
  3653. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGL.indexBuffer);
  3654. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, webGL.glIndicies, gl.STATIC_DRAW);
  3655. };
  3656. /**
  3657. * Builds a rectangle to draw
  3658. *
  3659. * @static
  3660. * @private
  3661. * @method buildRectangle
  3662. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  3663. * @param webGLData {Object}
  3664. */
  3665. PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData)
  3666. {
  3667. // --- //
  3668. // need to convert points to a nice regular data
  3669. //
  3670. var rectData = graphicsData.points;
  3671. var x = rectData[0];
  3672. var y = rectData[1];
  3673. var width = rectData[2];
  3674. var height = rectData[3];
  3675. if(graphicsData.fill)
  3676. {
  3677. var color = PIXI.hex2rgb(graphicsData.fillColor);
  3678. var alpha = graphicsData.fillAlpha;
  3679. var r = color[0] * alpha;
  3680. var g = color[1] * alpha;
  3681. var b = color[2] * alpha;
  3682. var verts = webGLData.points;
  3683. var indices = webGLData.indices;
  3684. var vertPos = verts.length/6;
  3685. // start
  3686. verts.push(x, y);
  3687. verts.push(r, g, b, alpha);
  3688. verts.push(x + width, y);
  3689. verts.push(r, g, b, alpha);
  3690. verts.push(x , y + height);
  3691. verts.push(r, g, b, alpha);
  3692. verts.push(x + width, y + height);
  3693. verts.push(r, g, b, alpha);
  3694. // insert 2 dead triangles..
  3695. indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3);
  3696. }
  3697. if(graphicsData.lineWidth)
  3698. {
  3699. var tempPoints = graphicsData.points;
  3700. graphicsData.points = [x, y,
  3701. x + width, y,
  3702. x + width, y + height,
  3703. x, y + height,
  3704. x, y];
  3705. PIXI.WebGLGraphics.buildLine(graphicsData, webGLData);
  3706. graphicsData.points = tempPoints;
  3707. }
  3708. };
  3709. /**
  3710. * Builds a circle to draw
  3711. *
  3712. * @static
  3713. * @private
  3714. * @method buildCircle
  3715. * @param graphicsData {Graphics} The graphics object to draw
  3716. * @param webGLData {Object}
  3717. */
  3718. PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData)
  3719. {
  3720. // need to convert points to a nice regular data
  3721. var rectData = graphicsData.points;
  3722. var x = rectData[0];
  3723. var y = rectData[1];
  3724. var width = rectData[2];
  3725. var height = rectData[3];
  3726. var totalSegs = 40;
  3727. var seg = (Math.PI * 2) / totalSegs ;
  3728. var i = 0;
  3729. if(graphicsData.fill)
  3730. {
  3731. var color = PIXI.hex2rgb(graphicsData.fillColor);
  3732. var alpha = graphicsData.fillAlpha;
  3733. var r = color[0] * alpha;
  3734. var g = color[1] * alpha;
  3735. var b = color[2] * alpha;
  3736. var verts = webGLData.points;
  3737. var indices = webGLData.indices;
  3738. var vecPos = verts.length/6;
  3739. indices.push(vecPos);
  3740. for (i = 0; i < totalSegs + 1 ; i++)
  3741. {
  3742. verts.push(x,y, r, g, b, alpha);
  3743. verts.push(x + Math.sin(seg * i) * width,
  3744. y + Math.cos(seg * i) * height,
  3745. r, g, b, alpha);
  3746. indices.push(vecPos++, vecPos++);
  3747. }
  3748. indices.push(vecPos-1);
  3749. }
  3750. if(graphicsData.lineWidth)
  3751. {
  3752. var tempPoints = graphicsData.points;
  3753. graphicsData.points = [];
  3754. for (i = 0; i < totalSegs + 1; i++)
  3755. {
  3756. graphicsData.points.push(x + Math.sin(seg * i) * width,
  3757. y + Math.cos(seg * i) * height);
  3758. }
  3759. PIXI.WebGLGraphics.buildLine(graphicsData, webGLData);
  3760. graphicsData.points = tempPoints;
  3761. }
  3762. };
  3763. /**
  3764. * Builds a line to draw
  3765. *
  3766. * @static
  3767. * @private
  3768. * @method buildLine
  3769. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  3770. * @param webGLData {Object}
  3771. */
  3772. PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData)
  3773. {
  3774. // TODO OPTIMISE!
  3775. var i = 0;
  3776. var points = graphicsData.points;
  3777. if(points.length === 0)return;
  3778. // if the line width is an odd number add 0.5 to align to a whole pixel
  3779. if(graphicsData.lineWidth%2)
  3780. {
  3781. for (i = 0; i < points.length; i++) {
  3782. points[i] += 0.5;
  3783. }
  3784. }
  3785. // get first and last point.. figure out the middle!
  3786. var firstPoint = new PIXI.Point( points[0], points[1] );
  3787. var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] );
  3788. // if the first point is the last point - gonna have issues :)
  3789. if(firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y)
  3790. {
  3791. points.pop();
  3792. points.pop();
  3793. lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] );
  3794. var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5;
  3795. var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5;
  3796. points.unshift(midPointX, midPointY);
  3797. points.push(midPointX, midPointY);
  3798. }
  3799. var verts = webGLData.points;
  3800. var indices = webGLData.indices;
  3801. var length = points.length / 2;
  3802. var indexCount = points.length;
  3803. var indexStart = verts.length/6;
  3804. // DRAW the Line
  3805. var width = graphicsData.lineWidth / 2;
  3806. // sort color
  3807. var color = PIXI.hex2rgb(graphicsData.lineColor);
  3808. var alpha = graphicsData.lineAlpha;
  3809. var r = color[0] * alpha;
  3810. var g = color[1] * alpha;
  3811. var b = color[2] * alpha;
  3812. var px, py, p1x, p1y, p2x, p2y, p3x, p3y;
  3813. var perpx, perpy, perp2x, perp2y, perp3x, perp3y;
  3814. var a1, b1, c1, a2, b2, c2;
  3815. var denom, pdist, dist;
  3816. p1x = points[0];
  3817. p1y = points[1];
  3818. p2x = points[2];
  3819. p2y = points[3];
  3820. perpx = -(p1y - p2y);
  3821. perpy = p1x - p2x;
  3822. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  3823. perpx /= dist;
  3824. perpy /= dist;
  3825. perpx *= width;
  3826. perpy *= width;
  3827. // start
  3828. verts.push(p1x - perpx , p1y - perpy,
  3829. r, g, b, alpha);
  3830. verts.push(p1x + perpx , p1y + perpy,
  3831. r, g, b, alpha);
  3832. for (i = 1; i < length-1; i++)
  3833. {
  3834. p1x = points[(i-1)*2];
  3835. p1y = points[(i-1)*2 + 1];
  3836. p2x = points[(i)*2];
  3837. p2y = points[(i)*2 + 1];
  3838. p3x = points[(i+1)*2];
  3839. p3y = points[(i+1)*2 + 1];
  3840. perpx = -(p1y - p2y);
  3841. perpy = p1x - p2x;
  3842. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  3843. perpx /= dist;
  3844. perpy /= dist;
  3845. perpx *= width;
  3846. perpy *= width;
  3847. perp2x = -(p2y - p3y);
  3848. perp2y = p2x - p3x;
  3849. dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y);
  3850. perp2x /= dist;
  3851. perp2y /= dist;
  3852. perp2x *= width;
  3853. perp2y *= width;
  3854. a1 = (-perpy + p1y) - (-perpy + p2y);
  3855. b1 = (-perpx + p2x) - (-perpx + p1x);
  3856. c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y);
  3857. a2 = (-perp2y + p3y) - (-perp2y + p2y);
  3858. b2 = (-perp2x + p2x) - (-perp2x + p3x);
  3859. c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y);
  3860. denom = a1*b2 - a2*b1;
  3861. if(Math.abs(denom) < 0.1 )
  3862. {
  3863. denom+=10.1;
  3864. verts.push(p2x - perpx , p2y - perpy,
  3865. r, g, b, alpha);
  3866. verts.push(p2x + perpx , p2y + perpy,
  3867. r, g, b, alpha);
  3868. continue;
  3869. }
  3870. px = (b1*c2 - b2*c1)/denom;
  3871. py = (a2*c1 - a1*c2)/denom;
  3872. pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y);
  3873. if(pdist > 140 * 140)
  3874. {
  3875. perp3x = perpx - perp2x;
  3876. perp3y = perpy - perp2y;
  3877. dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y);
  3878. perp3x /= dist;
  3879. perp3y /= dist;
  3880. perp3x *= width;
  3881. perp3y *= width;
  3882. verts.push(p2x - perp3x, p2y -perp3y);
  3883. verts.push(r, g, b, alpha);
  3884. verts.push(p2x + perp3x, p2y +perp3y);
  3885. verts.push(r, g, b, alpha);
  3886. verts.push(p2x - perp3x, p2y -perp3y);
  3887. verts.push(r, g, b, alpha);
  3888. indexCount++;
  3889. }
  3890. else
  3891. {
  3892. verts.push(px , py);
  3893. verts.push(r, g, b, alpha);
  3894. verts.push(p2x - (px-p2x), p2y - (py - p2y));
  3895. verts.push(r, g, b, alpha);
  3896. }
  3897. }
  3898. p1x = points[(length-2)*2];
  3899. p1y = points[(length-2)*2 + 1];
  3900. p2x = points[(length-1)*2];
  3901. p2y = points[(length-1)*2 + 1];
  3902. perpx = -(p1y - p2y);
  3903. perpy = p1x - p2x;
  3904. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  3905. perpx /= dist;
  3906. perpy /= dist;
  3907. perpx *= width;
  3908. perpy *= width;
  3909. verts.push(p2x - perpx , p2y - perpy);
  3910. verts.push(r, g, b, alpha);
  3911. verts.push(p2x + perpx , p2y + perpy);
  3912. verts.push(r, g, b, alpha);
  3913. indices.push(indexStart);
  3914. for (i = 0; i < indexCount; i++)
  3915. {
  3916. indices.push(indexStart++);
  3917. }
  3918. indices.push(indexStart-1);
  3919. };
  3920. /**
  3921. * Builds a polygon to draw
  3922. *
  3923. * @static
  3924. * @private
  3925. * @method buildPoly
  3926. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  3927. * @param webGLData {Object}
  3928. */
  3929. PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData)
  3930. {
  3931. var points = graphicsData.points;
  3932. if(points.length < 6)return;
  3933. // get first and last point.. figure out the middle!
  3934. var verts = webGLData.points;
  3935. var indices = webGLData.indices;
  3936. var length = points.length / 2;
  3937. // sort color
  3938. var color = PIXI.hex2rgb(graphicsData.fillColor);
  3939. var alpha = graphicsData.fillAlpha;
  3940. var r = color[0] * alpha;
  3941. var g = color[1] * alpha;
  3942. var b = color[2] * alpha;
  3943. var triangles = PIXI.PolyK.Triangulate(points);
  3944. var vertPos = verts.length / 6;
  3945. var i = 0;
  3946. for (i = 0; i < triangles.length; i+=3)
  3947. {
  3948. indices.push(triangles[i] + vertPos);
  3949. indices.push(triangles[i] + vertPos);
  3950. indices.push(triangles[i+1] + vertPos);
  3951. indices.push(triangles[i+2] +vertPos);
  3952. indices.push(triangles[i+2] + vertPos);
  3953. }
  3954. for (i = 0; i < length; i++)
  3955. {
  3956. verts.push(points[i * 2], points[i * 2 + 1],
  3957. r, g, b, alpha);
  3958. }
  3959. };
  3960. /**
  3961. * @author Mat Groves http://matgroves.com/ @Doormat23
  3962. */
  3963. PIXI.glContexts = []; // this is where we store the webGL contexts for easy access.
  3964. /**
  3965. * the WebGLRenderer draws the stage and all its content onto a webGL enabled canvas. This renderer
  3966. * should be used for browsers that support webGL. This Render works by automatically managing webGLBatch's.
  3967. * So no need for Sprite Batch's or Sprite Cloud's
  3968. * Dont forget to add the view to your DOM or you will not see anything :)
  3969. *
  3970. * @class WebGLRenderer
  3971. * @constructor
  3972. * @param width=0 {Number} the width of the canvas view
  3973. * @param height=0 {Number} the height of the canvas view
  3974. * @param view {HTMLCanvasElement} the canvas to use as a view, optional
  3975. * @param transparent=false {Boolean} If the render view is transparent, default false
  3976. * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment)
  3977. *
  3978. */
  3979. PIXI.WebGLRenderer = function(width, height, view, transparent, antialias)
  3980. {
  3981. if(!PIXI.defaultRenderer)PIXI.defaultRenderer = this;
  3982. this.type = PIXI.WEBGL_RENDERER;
  3983. // do a catch.. only 1 webGL renderer..
  3984. /**
  3985. * Whether the render view is transparent
  3986. *
  3987. * @property transparent
  3988. * @type Boolean
  3989. */
  3990. this.transparent = !!transparent;
  3991. /**
  3992. * The width of the canvas view
  3993. *
  3994. * @property width
  3995. * @type Number
  3996. * @default 800
  3997. */
  3998. this.width = width || 800;
  3999. /**
  4000. * The height of the canvas view
  4001. *
  4002. * @property height
  4003. * @type Number
  4004. * @default 600
  4005. */
  4006. this.height = height || 600;
  4007. /**
  4008. * The canvas element that everything is drawn to
  4009. *
  4010. * @property view
  4011. * @type HTMLCanvasElement
  4012. */
  4013. this.view = view || document.createElement( 'canvas' );
  4014. this.view.width = this.width;
  4015. this.view.height = this.height;
  4016. // deal with losing context..
  4017. this.contextLost = this.handleContextLost.bind(this);
  4018. this.contextRestoredLost = this.handleContextRestored.bind(this);
  4019. this.view.addEventListener('webglcontextlost', this.contextLost, false);
  4020. this.view.addEventListener('webglcontextrestored', this.contextRestoredLost, false);
  4021. this.options = {
  4022. alpha: this.transparent,
  4023. antialias:!!antialias, // SPEED UP??
  4024. premultipliedAlpha:!!transparent,
  4025. stencil:true
  4026. };
  4027. //try 'experimental-webgl'
  4028. try {
  4029. this.gl = this.view.getContext('experimental-webgl', this.options);
  4030. } catch (e) {
  4031. //try 'webgl'
  4032. try {
  4033. this.gl = this.view.getContext('webgl', this.options);
  4034. } catch (e2) {
  4035. // fail, not able to get a context
  4036. throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this);
  4037. }
  4038. }
  4039. var gl = this.gl;
  4040. this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++;
  4041. PIXI.glContexts[this.glContextId] = gl;
  4042. if(!PIXI.blendModesWebGL)
  4043. {
  4044. PIXI.blendModesWebGL = [];
  4045. PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4046. PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA];
  4047. PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA];
  4048. PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE];
  4049. PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4050. PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4051. PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4052. PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4053. PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4054. PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4055. PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4056. PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4057. PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4058. PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4059. PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4060. PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4061. PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  4062. }
  4063. this.projection = new PIXI.Point();
  4064. this.projection.x = this.width/2;
  4065. this.projection.y = -this.height/2;
  4066. this.offset = new PIXI.Point(0, 0);
  4067. this.resize(this.width, this.height);
  4068. this.contextLost = false;
  4069. // time to create the render managers! each one focuses on managine a state in webGL
  4070. this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs
  4071. this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites
  4072. this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer
  4073. this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters
  4074. this.renderSession = {};
  4075. this.renderSession.gl = this.gl;
  4076. this.renderSession.drawCount = 0;
  4077. this.renderSession.shaderManager = this.shaderManager;
  4078. this.renderSession.maskManager = this.maskManager;
  4079. this.renderSession.filterManager = this.filterManager;
  4080. this.renderSession.spriteBatch = this.spriteBatch;
  4081. this.renderSession.renderer = this;
  4082. gl.useProgram(this.shaderManager.defaultShader.program);
  4083. gl.disable(gl.DEPTH_TEST);
  4084. gl.disable(gl.CULL_FACE);
  4085. gl.enable(gl.BLEND);
  4086. gl.colorMask(true, true, true, this.transparent);
  4087. };
  4088. // constructor
  4089. PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer;
  4090. /**
  4091. * Renders the stage to its webGL view
  4092. *
  4093. * @method render
  4094. * @param stage {Stage} the Stage element to be rendered
  4095. */
  4096. PIXI.WebGLRenderer.prototype.render = function(stage)
  4097. {
  4098. if(this.contextLost)return;
  4099. // if rendering a new stage clear the batches..
  4100. if(this.__stage !== stage)
  4101. {
  4102. if(stage.interactive)stage.interactionManager.removeEvents();
  4103. // TODO make this work
  4104. // dont think this is needed any more?
  4105. this.__stage = stage;
  4106. }
  4107. // update any textures this includes uvs and uploading them to the gpu
  4108. PIXI.WebGLRenderer.updateTextures();
  4109. // update the scene graph
  4110. stage.updateTransform();
  4111. // interaction
  4112. if(stage._interactive)
  4113. {
  4114. //need to add some events!
  4115. if(!stage._interactiveEventsAdded)
  4116. {
  4117. stage._interactiveEventsAdded = true;
  4118. stage.interactionManager.setTarget(this);
  4119. }
  4120. }
  4121. var gl = this.gl;
  4122. // -- Does this need to be set every frame? -- //
  4123. //gl.colorMask(true, true, true, this.transparent);
  4124. gl.viewport(0, 0, this.width, this.height);
  4125. // make sure we are bound to the main frame buffer
  4126. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  4127. if(this.transparent)
  4128. {
  4129. gl.clearColor(0, 0, 0, 0);
  4130. }
  4131. else
  4132. {
  4133. gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1);
  4134. }
  4135. gl.clear(gl.COLOR_BUFFER_BIT);
  4136. this.renderDisplayObject( stage, this.projection );
  4137. // interaction
  4138. if(stage.interactive)
  4139. {
  4140. //need to add some events!
  4141. if(!stage._interactiveEventsAdded)
  4142. {
  4143. stage._interactiveEventsAdded = true;
  4144. stage.interactionManager.setTarget(this);
  4145. }
  4146. }
  4147. else
  4148. {
  4149. if(stage._interactiveEventsAdded)
  4150. {
  4151. stage._interactiveEventsAdded = false;
  4152. stage.interactionManager.setTarget(this);
  4153. }
  4154. }
  4155. /*
  4156. //can simulate context loss in Chrome like so:
  4157. this.view.onmousedown = function(ev) {
  4158. console.dir(this.gl.getSupportedExtensions());
  4159. var ext = (
  4160. gl.getExtension("WEBGL_scompressed_texture_s3tc")
  4161. // gl.getExtension("WEBGL_compressed_texture_s3tc") ||
  4162. // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") ||
  4163. // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc")
  4164. );
  4165. console.dir(ext);
  4166. var loseCtx = this.gl.getExtension("WEBGL_lose_context");
  4167. console.log("killing context");
  4168. loseCtx.loseContext();
  4169. setTimeout(function() {
  4170. console.log("restoring context...");
  4171. loseCtx.restoreContext();
  4172. }.bind(this), 1000);
  4173. }.bind(this);
  4174. */
  4175. };
  4176. /**
  4177. * Renders a display Object
  4178. *
  4179. * @method renderDIsplayObject
  4180. * @param displayObject {DisplayObject} The DisplayObject to render
  4181. * @param projection {Point} The projection
  4182. * @param buffer {Array} a standard WebGL buffer
  4183. */
  4184. PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer)
  4185. {
  4186. // reset the render session data..
  4187. this.renderSession.drawCount = 0;
  4188. this.renderSession.currentBlendMode = 9999;
  4189. this.renderSession.projection = projection;
  4190. this.renderSession.offset = this.offset;
  4191. // start the sprite batch
  4192. this.spriteBatch.begin(this.renderSession);
  4193. // start the filter manager
  4194. this.filterManager.begin(this.renderSession, buffer);
  4195. // render the scene!
  4196. displayObject._renderWebGL(this.renderSession);
  4197. // finish the sprite batch
  4198. this.spriteBatch.end();
  4199. };
  4200. /**
  4201. * Updates the textures loaded into this webgl renderer
  4202. *
  4203. * @static
  4204. * @method updateTextures
  4205. * @private
  4206. */
  4207. PIXI.WebGLRenderer.updateTextures = function()
  4208. {
  4209. var i = 0;
  4210. //TODO break this out into a texture manager...
  4211. //for (i = 0; i < PIXI.texturesToUpdate.length; i++)
  4212. // PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]);
  4213. for (i=0; i < PIXI.Texture.frameUpdates.length; i++)
  4214. PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]);
  4215. for (i = 0; i < PIXI.texturesToDestroy.length; i++)
  4216. PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]);
  4217. PIXI.texturesToUpdate.length = 0;
  4218. PIXI.texturesToDestroy.length = 0;
  4219. PIXI.Texture.frameUpdates.length = 0;
  4220. };
  4221. /**
  4222. * Destroys a loaded webgl texture
  4223. *
  4224. * @method destroyTexture
  4225. * @param texture {Texture} The texture to update
  4226. * @private
  4227. */
  4228. PIXI.WebGLRenderer.destroyTexture = function(texture)
  4229. {
  4230. //TODO break this out into a texture manager...
  4231. for (var i = texture._glTextures.length - 1; i >= 0; i--)
  4232. {
  4233. var glTexture = texture._glTextures[i];
  4234. var gl = PIXI.glContexts[i];
  4235. if(gl && glTexture)
  4236. {
  4237. gl.deleteTexture(glTexture);
  4238. }
  4239. }
  4240. texture._glTextures.length = 0;
  4241. };
  4242. /**
  4243. *
  4244. * @method updateTextureFrame
  4245. * @param texture {Texture} The texture to update the frame from
  4246. * @private
  4247. */
  4248. PIXI.WebGLRenderer.updateTextureFrame = function(texture)
  4249. {
  4250. texture.updateFrame = false;
  4251. // now set the uvs. Figured that the uv data sits with a texture rather than a sprite.
  4252. // so uv data is stored on the texture itself
  4253. texture._updateWebGLuvs();
  4254. };
  4255. /**
  4256. * resizes the webGL view to the specified width and height
  4257. *
  4258. * @method resize
  4259. * @param width {Number} the new width of the webGL view
  4260. * @param height {Number} the new height of the webGL view
  4261. */
  4262. PIXI.WebGLRenderer.prototype.resize = function(width, height)
  4263. {
  4264. this.width = width;
  4265. this.height = height;
  4266. this.view.width = width;
  4267. this.view.height = height;
  4268. this.gl.viewport(0, 0, this.width, this.height);
  4269. this.projection.x = this.width/2;
  4270. this.projection.y = -this.height/2;
  4271. };
  4272. /**
  4273. * Creates a WebGL texture
  4274. *
  4275. * @method createWebGLTexture
  4276. * @param texture {Texture} the texture to render
  4277. * @param gl {webglContext} the WebGL context
  4278. * @static
  4279. */
  4280. PIXI.createWebGLTexture = function(texture, gl)
  4281. {
  4282. if(texture.hasLoaded)
  4283. {
  4284. texture._glTextures[gl.id] = gl.createTexture();
  4285. gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]);
  4286. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  4287. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source);
  4288. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  4289. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  4290. // reguler...
  4291. if(!texture._powerOf2)
  4292. {
  4293. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  4294. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  4295. }
  4296. else
  4297. {
  4298. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  4299. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
  4300. }
  4301. gl.bindTexture(gl.TEXTURE_2D, null);
  4302. }
  4303. return texture._glTextures[gl.id];
  4304. };
  4305. /**
  4306. * Updates a WebGL texture
  4307. *
  4308. * @method updateWebGLTexture
  4309. * @param texture {Texture} the texture to update
  4310. * @param gl {webglContext} the WebGL context
  4311. * @private
  4312. */
  4313. PIXI.updateWebGLTexture = function(texture, gl)
  4314. {
  4315. if( texture._glTextures[gl.id] )
  4316. {
  4317. gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]);
  4318. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  4319. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source);
  4320. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  4321. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  4322. // reguler...
  4323. if(!texture._powerOf2)
  4324. {
  4325. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  4326. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  4327. }
  4328. else
  4329. {
  4330. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  4331. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
  4332. }
  4333. gl.bindTexture(gl.TEXTURE_2D, null);
  4334. }
  4335. };
  4336. /**
  4337. * Handles a lost webgl context
  4338. *
  4339. * @method handleContextLost
  4340. * @param event {Event}
  4341. * @private
  4342. */
  4343. PIXI.WebGLRenderer.prototype.handleContextLost = function(event)
  4344. {
  4345. event.preventDefault();
  4346. this.contextLost = true;
  4347. };
  4348. /**
  4349. * Handles a restored webgl context
  4350. *
  4351. * @method handleContextRestored
  4352. * @param event {Event}
  4353. * @private
  4354. */
  4355. PIXI.WebGLRenderer.prototype.handleContextRestored = function()
  4356. {
  4357. //try 'experimental-webgl'
  4358. try {
  4359. this.gl = this.view.getContext('experimental-webgl', this.options);
  4360. } catch (e) {
  4361. //try 'webgl'
  4362. try {
  4363. this.gl = this.view.getContext('webgl', this.options);
  4364. } catch (e2) {
  4365. // fail, not able to get a context
  4366. throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this);
  4367. }
  4368. }
  4369. var gl = this.gl;
  4370. gl.id = PIXI.WebGLRenderer.glContextId ++;
  4371. // need to set the context...
  4372. this.shaderManager.setContext(gl);
  4373. this.spriteBatch.setContext(gl);
  4374. this.maskManager.setContext(gl);
  4375. this.filterManager.setContext(gl);
  4376. this.renderSession.gl = this.gl;
  4377. gl.disable(gl.DEPTH_TEST);
  4378. gl.disable(gl.CULL_FACE);
  4379. gl.enable(gl.BLEND);
  4380. gl.colorMask(true, true, true, this.transparent);
  4381. this.gl.viewport(0, 0, this.width, this.height);
  4382. for(var key in PIXI.TextureCache)
  4383. {
  4384. var texture = PIXI.TextureCache[key].baseTexture;
  4385. texture._glTextures = [];
  4386. }
  4387. /**
  4388. * Whether the context was lost
  4389. * @property contextLost
  4390. * @type Boolean
  4391. */
  4392. this.contextLost = false;
  4393. };
  4394. /**
  4395. * Removes everything from the renderer (event listeners, spritebatch, etc...)
  4396. *
  4397. * @method destroy
  4398. */
  4399. PIXI.WebGLRenderer.prototype.destroy = function()
  4400. {
  4401. // deal with losing context..
  4402. // remove listeners
  4403. this.view.removeEventListener('webglcontextlost', this.contextLost);
  4404. this.view.removeEventListener('webglcontextrestored', this.contextRestoredLost);
  4405. PIXI.glContexts[this.glContextId] = null;
  4406. this.projection = null;
  4407. this.offset = null;
  4408. // time to create the render managers! each one focuses on managine a state in webGL
  4409. this.shaderManager.destroy();
  4410. this.spriteBatch.destroy();
  4411. this.maskManager.destroy();
  4412. this.filterManager.destroy();
  4413. this.shaderManager = null;
  4414. this.spriteBatch = null;
  4415. this.maskManager = null;
  4416. this.filterManager = null;
  4417. this.gl = null;
  4418. //
  4419. this.renderSession = null;
  4420. };
  4421. PIXI.WebGLRenderer.glContextId = 0;
  4422. /**
  4423. * @author Mat Groves http://matgroves.com/ @Doormat23
  4424. */
  4425. /**
  4426. * @class WebGLMaskManager
  4427. * @constructor
  4428. * @param gl {WebGLContext} the current WebGL drawing context
  4429. * @private
  4430. */
  4431. PIXI.WebGLMaskManager = function(gl)
  4432. {
  4433. this.maskStack = [];
  4434. this.maskPosition = 0;
  4435. this.setContext(gl);
  4436. };
  4437. /**
  4438. * Sets the drawing context to the one given in parameter
  4439. * @method setContext
  4440. * @param gl {WebGLContext} the current WebGL drawing context
  4441. */
  4442. PIXI.WebGLMaskManager.prototype.setContext = function(gl)
  4443. {
  4444. this.gl = gl;
  4445. };
  4446. /**
  4447. * Applies the Mask and adds it to the current filter stack
  4448. * @method pushMask
  4449. * @param maskData {Array}
  4450. * @param renderSession {RenderSession}
  4451. */
  4452. PIXI.WebGLMaskManager.prototype.pushMask = function(maskData, renderSession)
  4453. {
  4454. var gl = this.gl;
  4455. if(this.maskStack.length === 0)
  4456. {
  4457. gl.enable(gl.STENCIL_TEST);
  4458. gl.stencilFunc(gl.ALWAYS,1,1);
  4459. }
  4460. // maskData.visible = false;
  4461. this.maskStack.push(maskData);
  4462. gl.colorMask(false, false, false, true);
  4463. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
  4464. PIXI.WebGLGraphics.renderGraphics(maskData, renderSession);
  4465. gl.colorMask(true, true, true, true);
  4466. gl.stencilFunc(gl.NOTEQUAL,0, this.maskStack.length);
  4467. gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
  4468. };
  4469. /**
  4470. * Removes the last filter from the filter stack and doesn't return it
  4471. * @method popMask
  4472. *
  4473. * @param renderSession {RenderSession} an object containing all the useful parameters
  4474. */
  4475. PIXI.WebGLMaskManager.prototype.popMask = function(renderSession)
  4476. {
  4477. var gl = this.gl;
  4478. var maskData = this.maskStack.pop();
  4479. if(maskData)
  4480. {
  4481. gl.colorMask(false, false, false, false);
  4482. //gl.stencilFunc(gl.ALWAYS,1,1);
  4483. gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
  4484. PIXI.WebGLGraphics.renderGraphics(maskData, renderSession);
  4485. gl.colorMask(true, true, true, true);
  4486. gl.stencilFunc(gl.NOTEQUAL,0,this.maskStack.length);
  4487. gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
  4488. }
  4489. if(this.maskStack.length === 0)gl.disable(gl.STENCIL_TEST);
  4490. };
  4491. /**
  4492. * Destroys the mask stack
  4493. * @method destroy
  4494. */
  4495. PIXI.WebGLMaskManager.prototype.destroy = function()
  4496. {
  4497. this.maskStack = null;
  4498. this.gl = null;
  4499. };
  4500. /**
  4501. * @author Mat Groves http://matgroves.com/ @Doormat23
  4502. */
  4503. /**
  4504. * @class WebGLShaderManager
  4505. * @constructor
  4506. * @param gl {WebGLContext} the current WebGL drawing context
  4507. * @private
  4508. */
  4509. PIXI.WebGLShaderManager = function(gl)
  4510. {
  4511. this.maxAttibs = 10;
  4512. this.attribState = [];
  4513. this.tempAttribState = [];
  4514. for (var i = 0; i < this.maxAttibs; i++) {
  4515. this.attribState[i] = false;
  4516. }
  4517. this.setContext(gl);
  4518. // the final one is used for the rendering strips
  4519. //this.stripShader = new PIXI.StripShader(gl);
  4520. };
  4521. /**
  4522. * Initialises the context and the properties
  4523. * @method setContext
  4524. * @param gl {WebGLContext} the current WebGL drawing context
  4525. * @param transparent {Boolean} Whether or not the drawing context should be transparent
  4526. */
  4527. PIXI.WebGLShaderManager.prototype.setContext = function(gl)
  4528. {
  4529. this.gl = gl;
  4530. // the next one is used for rendering primatives
  4531. this.primitiveShader = new PIXI.PrimitiveShader(gl);
  4532. // this shader is used for the default sprite rendering
  4533. this.defaultShader = new PIXI.PixiShader(gl);
  4534. // this shader is used for the fast sprite rendering
  4535. this.fastShader = new PIXI.PixiFastShader(gl);
  4536. this.activateShader(this.defaultShader);
  4537. };
  4538. /**
  4539. * Takes the attributes given in parameters
  4540. * @method setAttribs
  4541. * @param attribs {Array} attribs
  4542. */
  4543. PIXI.WebGLShaderManager.prototype.setAttribs = function(attribs)
  4544. {
  4545. // reset temp state
  4546. var i;
  4547. for (i = 0; i < this.tempAttribState.length; i++)
  4548. {
  4549. this.tempAttribState[i] = false;
  4550. }
  4551. // set the new attribs
  4552. for (i = 0; i < attribs.length; i++)
  4553. {
  4554. var attribId = attribs[i];
  4555. this.tempAttribState[attribId] = true;
  4556. }
  4557. var gl = this.gl;
  4558. for (i = 0; i < this.attribState.length; i++)
  4559. {
  4560. if(this.attribState[i] !== this.tempAttribState[i])
  4561. {
  4562. this.attribState[i] = this.tempAttribState[i];
  4563. if(this.tempAttribState[i])
  4564. {
  4565. gl.enableVertexAttribArray(i);
  4566. }
  4567. else
  4568. {
  4569. gl.disableVertexAttribArray(i);
  4570. }
  4571. }
  4572. }
  4573. };
  4574. /**
  4575. * Sets-up the given shader
  4576. *
  4577. * @method activateShader
  4578. * @param shader {Object} the shader that is going to be activated
  4579. */
  4580. PIXI.WebGLShaderManager.prototype.activateShader = function(shader)
  4581. {
  4582. //if(this.currentShader == shader)return;
  4583. this.currentShader = shader;
  4584. this.gl.useProgram(shader.program);
  4585. this.setAttribs(shader.attributes);
  4586. };
  4587. /**
  4588. * Triggers the primitive shader
  4589. * @method activatePrimitiveShader
  4590. */
  4591. PIXI.WebGLShaderManager.prototype.activatePrimitiveShader = function()
  4592. {
  4593. var gl = this.gl;
  4594. gl.useProgram(this.primitiveShader.program);
  4595. this.setAttribs(this.primitiveShader.attributes);
  4596. };
  4597. /**
  4598. * Disable the primitive shader
  4599. * @method deactivatePrimitiveShader
  4600. */
  4601. PIXI.WebGLShaderManager.prototype.deactivatePrimitiveShader = function()
  4602. {
  4603. var gl = this.gl;
  4604. gl.useProgram(this.defaultShader.program);
  4605. this.setAttribs(this.defaultShader.attributes);
  4606. };
  4607. /**
  4608. * Destroys
  4609. * @method destroy
  4610. */
  4611. PIXI.WebGLShaderManager.prototype.destroy = function()
  4612. {
  4613. this.attribState = null;
  4614. this.tempAttribState = null;
  4615. this.primitiveShader.destroy();
  4616. this.defaultShader.destroy();
  4617. this.fastShader.destroy();
  4618. this.gl = null;
  4619. };
  4620. /**
  4621. * @author Mat Groves
  4622. *
  4623. * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
  4624. * for creating the original pixi version!
  4625. *
  4626. * Heavily inspired by LibGDX's WebGLSpriteBatch:
  4627. * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
  4628. */
  4629. /**
  4630. *
  4631. * @class WebGLSpriteBatch
  4632. * @private
  4633. * @constructor
  4634. * @param gl {WebGLContext} the current WebGL drawing context
  4635. *
  4636. */
  4637. PIXI.WebGLSpriteBatch = function(gl)
  4638. {
  4639. /**
  4640. *
  4641. *
  4642. * @property vertSize
  4643. * @type Number
  4644. */
  4645. this.vertSize = 6;
  4646. /**
  4647. * The number of images in the SpriteBatch before it flushes
  4648. * @property size
  4649. * @type Number
  4650. */
  4651. this.size = 2000;//Math.pow(2, 16) / this.vertSize;
  4652. //the total number of floats in our batch
  4653. var numVerts = this.size * 4 * this.vertSize;
  4654. //the total number of indices in our batch
  4655. var numIndices = this.size * 6;
  4656. //vertex data
  4657. /**
  4658. * Holds the vertices
  4659. *
  4660. * @property vertices
  4661. * @type Float32Array
  4662. */
  4663. this.vertices = new Float32Array(numVerts);
  4664. //index data
  4665. /**
  4666. * Holds the indices
  4667. *
  4668. * @property indices
  4669. * @type Uint16Array
  4670. */
  4671. this.indices = new Uint16Array(numIndices);
  4672. this.lastIndexCount = 0;
  4673. for (var i=0, j=0; i < numIndices; i += 6, j += 4)
  4674. {
  4675. this.indices[i + 0] = j + 0;
  4676. this.indices[i + 1] = j + 1;
  4677. this.indices[i + 2] = j + 2;
  4678. this.indices[i + 3] = j + 0;
  4679. this.indices[i + 4] = j + 2;
  4680. this.indices[i + 5] = j + 3;
  4681. }
  4682. this.drawing = false;
  4683. this.currentBatchSize = 0;
  4684. this.currentBaseTexture = null;
  4685. this.setContext(gl);
  4686. };
  4687. /**
  4688. *
  4689. * @method setContext
  4690. *
  4691. * @param gl {WebGLContext} the current WebGL drawing context
  4692. */
  4693. PIXI.WebGLSpriteBatch.prototype.setContext = function(gl)
  4694. {
  4695. this.gl = gl;
  4696. // create a couple of buffers
  4697. this.vertexBuffer = gl.createBuffer();
  4698. this.indexBuffer = gl.createBuffer();
  4699. // 65535 is max index, so 65535 / 6 = 10922.
  4700. //upload the index data
  4701. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  4702. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  4703. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  4704. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
  4705. this.currentBlendMode = 99999;
  4706. };
  4707. /**
  4708. *
  4709. * @method begin
  4710. *
  4711. * @param renderSession {RenderSession} the RenderSession
  4712. */
  4713. PIXI.WebGLSpriteBatch.prototype.begin = function(renderSession)
  4714. {
  4715. this.renderSession = renderSession;
  4716. this.shader = this.renderSession.shaderManager.defaultShader;
  4717. this.start();
  4718. };
  4719. /**
  4720. *
  4721. * @method end
  4722. *
  4723. */
  4724. PIXI.WebGLSpriteBatch.prototype.end = function()
  4725. {
  4726. this.flush();
  4727. };
  4728. /**
  4729. *
  4730. * @method render
  4731. *
  4732. * @param sprite {Sprite} the sprite to render when using this spritebatch
  4733. */
  4734. PIXI.WebGLSpriteBatch.prototype.render = function(sprite)
  4735. {
  4736. var texture = sprite.texture;
  4737. // check texture..
  4738. if(texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
  4739. {
  4740. this.flush();
  4741. this.currentBaseTexture = texture.baseTexture;
  4742. }
  4743. // check blend mode
  4744. if(sprite.blendMode !== this.currentBlendMode)
  4745. {
  4746. this.setBlendMode(sprite.blendMode);
  4747. }
  4748. // get the uvs for the texture
  4749. var uvs = sprite._uvs || sprite.texture._uvs;
  4750. // if the uvs have not updated then no point rendering just yet!
  4751. if(!uvs)return;
  4752. // get the sprites current alpha
  4753. var alpha = sprite.worldAlpha;
  4754. var tint = sprite.tint;
  4755. var verticies = this.vertices;
  4756. // TODO trim??
  4757. var aX = sprite.anchor.x;
  4758. var aY = sprite.anchor.y;
  4759. var w0, w1, h0, h1;
  4760. if (sprite.texture.trim)
  4761. {
  4762. // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
  4763. var trim = sprite.texture.trim;
  4764. w1 = trim.x - aX * trim.width;
  4765. w0 = w1 + texture.frame.width;
  4766. h1 = trim.y - aY * trim.height;
  4767. h0 = h1 + texture.frame.height;
  4768. }
  4769. else
  4770. {
  4771. w0 = (texture.frame.width ) * (1-aX);
  4772. w1 = (texture.frame.width ) * -aX;
  4773. h0 = texture.frame.height * (1-aY);
  4774. h1 = texture.frame.height * -aY;
  4775. }
  4776. var index = this.currentBatchSize * 4 * this.vertSize;
  4777. var worldTransform = sprite.worldTransform;//.toArray();
  4778. var a = worldTransform.a;//[0];
  4779. var b = worldTransform.c;//[3];
  4780. var c = worldTransform.b;//[1];
  4781. var d = worldTransform.d;//[4];
  4782. var tx = worldTransform.tx;//[2];
  4783. var ty = worldTransform.ty;///[5];
  4784. // xy
  4785. verticies[index++] = a * w1 + c * h1 + tx;
  4786. verticies[index++] = d * h1 + b * w1 + ty;
  4787. // uv
  4788. verticies[index++] = uvs.x0;
  4789. verticies[index++] = uvs.y0;
  4790. // color
  4791. verticies[index++] = alpha;
  4792. verticies[index++] = tint;
  4793. // xy
  4794. verticies[index++] = a * w0 + c * h1 + tx;
  4795. verticies[index++] = d * h1 + b * w0 + ty;
  4796. // uv
  4797. verticies[index++] = uvs.x1;
  4798. verticies[index++] = uvs.y1;
  4799. // color
  4800. verticies[index++] = alpha;
  4801. verticies[index++] = tint;
  4802. // xy
  4803. verticies[index++] = a * w0 + c * h0 + tx;
  4804. verticies[index++] = d * h0 + b * w0 + ty;
  4805. // uv
  4806. verticies[index++] = uvs.x2;
  4807. verticies[index++] = uvs.y2;
  4808. // color
  4809. verticies[index++] = alpha;
  4810. verticies[index++] = tint;
  4811. // xy
  4812. verticies[index++] = a * w1 + c * h0 + tx;
  4813. verticies[index++] = d * h0 + b * w1 + ty;
  4814. // uv
  4815. verticies[index++] = uvs.x3;
  4816. verticies[index++] = uvs.y3;
  4817. // color
  4818. verticies[index++] = alpha;
  4819. verticies[index++] = tint;
  4820. // increment the batchsize
  4821. this.currentBatchSize++;
  4822. };
  4823. /**
  4824. * Renders a tilingSprite using the spriteBatch
  4825. * @method renderTilingSprite
  4826. *
  4827. * @param sprite {TilingSprite} the tilingSprite to render
  4828. */
  4829. PIXI.WebGLSpriteBatch.prototype.renderTilingSprite = function(tilingSprite)
  4830. {
  4831. var texture = tilingSprite.tilingTexture;
  4832. if(texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
  4833. {
  4834. this.flush();
  4835. this.currentBaseTexture = texture.baseTexture;
  4836. }
  4837. // check blend mode
  4838. if(tilingSprite.blendMode !== this.currentBlendMode)
  4839. {
  4840. this.setBlendMode(tilingSprite.blendMode);
  4841. }
  4842. // set the textures uvs temporarily
  4843. // TODO create a separate texture so that we can tile part of a texture
  4844. if(!tilingSprite._uvs)tilingSprite._uvs = new PIXI.TextureUvs();
  4845. var uvs = tilingSprite._uvs;
  4846. tilingSprite.tilePosition.x %= texture.baseTexture.width * tilingSprite.tileScaleOffset.x;
  4847. tilingSprite.tilePosition.y %= texture.baseTexture.height * tilingSprite.tileScaleOffset.y;
  4848. var offsetX = tilingSprite.tilePosition.x/(texture.baseTexture.width*tilingSprite.tileScaleOffset.x);
  4849. var offsetY = tilingSprite.tilePosition.y/(texture.baseTexture.height*tilingSprite.tileScaleOffset.y);
  4850. var scaleX = (tilingSprite.width / texture.baseTexture.width) / (tilingSprite.tileScale.x * tilingSprite.tileScaleOffset.x);
  4851. var scaleY = (tilingSprite.height / texture.baseTexture.height) / (tilingSprite.tileScale.y * tilingSprite.tileScaleOffset.y);
  4852. uvs.x0 = 0 - offsetX;
  4853. uvs.y0 = 0 - offsetY;
  4854. uvs.x1 = (1 * scaleX) - offsetX;
  4855. uvs.y1 = 0 - offsetY;
  4856. uvs.x2 = (1 * scaleX) - offsetX;
  4857. uvs.y2 = (1 * scaleY) - offsetY;
  4858. uvs.x3 = 0 - offsetX;
  4859. uvs.y3 = (1 *scaleY) - offsetY;
  4860. // get the tilingSprites current alpha
  4861. var alpha = tilingSprite.worldAlpha;
  4862. var tint = tilingSprite.tint;
  4863. var verticies = this.vertices;
  4864. var width = tilingSprite.width;
  4865. var height = tilingSprite.height;
  4866. // TODO trim??
  4867. var aX = tilingSprite.anchor.x; // - tilingSprite.texture.trim.x
  4868. var aY = tilingSprite.anchor.y; //- tilingSprite.texture.trim.y
  4869. var w0 = width * (1-aX);
  4870. var w1 = width * -aX;
  4871. var h0 = height * (1-aY);
  4872. var h1 = height * -aY;
  4873. var index = this.currentBatchSize * 4 * this.vertSize;
  4874. var worldTransform = tilingSprite.worldTransform;
  4875. var a = worldTransform.a;//[0];
  4876. var b = worldTransform.c;//[3];
  4877. var c = worldTransform.b;//[1];
  4878. var d = worldTransform.d;//[4];
  4879. var tx = worldTransform.tx;//[2];
  4880. var ty = worldTransform.ty;///[5];
  4881. // xy
  4882. verticies[index++] = a * w1 + c * h1 + tx;
  4883. verticies[index++] = d * h1 + b * w1 + ty;
  4884. // uv
  4885. verticies[index++] = uvs.x0;
  4886. verticies[index++] = uvs.y0;
  4887. // color
  4888. verticies[index++] = alpha;
  4889. verticies[index++] = tint;
  4890. // xy
  4891. verticies[index++] = a * w0 + c * h1 + tx;
  4892. verticies[index++] = d * h1 + b * w0 + ty;
  4893. // uv
  4894. verticies[index++] = uvs.x1;
  4895. verticies[index++] = uvs.y1;
  4896. // color
  4897. verticies[index++] = alpha;
  4898. verticies[index++] = tint;
  4899. // xy
  4900. verticies[index++] = a * w0 + c * h0 + tx;
  4901. verticies[index++] = d * h0 + b * w0 + ty;
  4902. // uv
  4903. verticies[index++] = uvs.x2;
  4904. verticies[index++] = uvs.y2;
  4905. // color
  4906. verticies[index++] = alpha;
  4907. verticies[index++] = tint;
  4908. // xy
  4909. verticies[index++] = a * w1 + c * h0 + tx;
  4910. verticies[index++] = d * h0 + b * w1 + ty;
  4911. // uv
  4912. verticies[index++] = uvs.x3;
  4913. verticies[index++] = uvs.y3;
  4914. // color
  4915. verticies[index++] = alpha;
  4916. verticies[index++] = tint;
  4917. // increment the batchs
  4918. this.currentBatchSize++;
  4919. };
  4920. /**
  4921. * Renders the content and empties the current batch
  4922. *
  4923. * @method flush
  4924. *
  4925. */
  4926. PIXI.WebGLSpriteBatch.prototype.flush = function()
  4927. {
  4928. // If the batch is length 0 then return as there is nothing to draw
  4929. if (this.currentBatchSize===0)return;
  4930. var gl = this.gl;
  4931. // bind the current texture
  4932. gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.currentBaseTexture, gl));
  4933. // upload the verts to the buffer
  4934. if(this.currentBatchSize > ( this.size * 0.5 ) )
  4935. {
  4936. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
  4937. }
  4938. else
  4939. {
  4940. var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
  4941. gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
  4942. }
  4943. // var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
  4944. //gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
  4945. // now draw those suckas!
  4946. gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0);
  4947. // then reset the batch!
  4948. this.currentBatchSize = 0;
  4949. // increment the draw count
  4950. this.renderSession.drawCount++;
  4951. };
  4952. /**
  4953. *
  4954. * @method stop
  4955. *
  4956. */
  4957. PIXI.WebGLSpriteBatch.prototype.stop = function()
  4958. {
  4959. this.flush();
  4960. };
  4961. /**
  4962. *
  4963. * @method start
  4964. *
  4965. */
  4966. PIXI.WebGLSpriteBatch.prototype.start = function()
  4967. {
  4968. var gl = this.gl;
  4969. // bind the main texture
  4970. gl.activeTexture(gl.TEXTURE0);
  4971. // bind the buffers
  4972. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  4973. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  4974. // set the projection
  4975. var projection = this.renderSession.projection;
  4976. gl.uniform2f(this.shader.projectionVector, projection.x, projection.y);
  4977. // set the pointers
  4978. var stride = this.vertSize * 4;
  4979. gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
  4980. gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4);
  4981. gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4);
  4982. // set the blend mode..
  4983. if(this.currentBlendMode !== PIXI.blendModes.NORMAL)
  4984. {
  4985. this.setBlendMode(PIXI.blendModes.NORMAL);
  4986. }
  4987. };
  4988. /**
  4989. * Sets-up the given blendMode from WebGL's point of view
  4990. * @method setBlendMode
  4991. *
  4992. * @param blendMode {Number} the blendMode, should be a Pixi const, such as PIXI.BlendModes.ADD
  4993. */
  4994. PIXI.WebGLSpriteBatch.prototype.setBlendMode = function(blendMode)
  4995. {
  4996. this.flush();
  4997. this.currentBlendMode = blendMode;
  4998. var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
  4999. this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
  5000. };
  5001. /**
  5002. * Destroys the SpriteBatch
  5003. * @method destroy
  5004. */
  5005. PIXI.WebGLSpriteBatch.prototype.destroy = function()
  5006. {
  5007. this.vertices = null;
  5008. this.indices = null;
  5009. this.gl.deleteBuffer( this.vertexBuffer );
  5010. this.gl.deleteBuffer( this.indexBuffer );
  5011. this.currentBaseTexture = null;
  5012. this.gl = null;
  5013. };
  5014. /**
  5015. * @author Mat Groves
  5016. *
  5017. * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
  5018. * for creating the original pixi version!
  5019. *
  5020. * Heavily inspired by LibGDX's WebGLSpriteBatch:
  5021. * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
  5022. */
  5023. PIXI.WebGLFastSpriteBatch = function(gl)
  5024. {
  5025. this.vertSize = 10;
  5026. this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize;
  5027. this.size = this.maxSize;
  5028. //the total number of floats in our batch
  5029. var numVerts = this.size * 4 * this.vertSize;
  5030. //the total number of indices in our batch
  5031. var numIndices = this.maxSize * 6;
  5032. //vertex data
  5033. this.vertices = new Float32Array(numVerts);
  5034. //index data
  5035. this.indices = new Uint16Array(numIndices);
  5036. this.vertexBuffer = null;
  5037. this.indexBuffer = null;
  5038. this.lastIndexCount = 0;
  5039. for (var i=0, j=0; i < numIndices; i += 6, j += 4)
  5040. {
  5041. this.indices[i + 0] = j + 0;
  5042. this.indices[i + 1] = j + 1;
  5043. this.indices[i + 2] = j + 2;
  5044. this.indices[i + 3] = j + 0;
  5045. this.indices[i + 4] = j + 2;
  5046. this.indices[i + 5] = j + 3;
  5047. }
  5048. this.drawing = false;
  5049. this.currentBatchSize = 0;
  5050. this.currentBaseTexture = null;
  5051. this.currentBlendMode = 0;
  5052. this.renderSession = null;
  5053. this.shader = null;
  5054. this.matrix = null;
  5055. this.setContext(gl);
  5056. };
  5057. PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl)
  5058. {
  5059. this.gl = gl;
  5060. // create a couple of buffers
  5061. this.vertexBuffer = gl.createBuffer();
  5062. this.indexBuffer = gl.createBuffer();
  5063. // 65535 is max index, so 65535 / 6 = 10922.
  5064. //upload the index data
  5065. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  5066. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  5067. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5068. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
  5069. this.currentBlendMode = 99999;
  5070. };
  5071. PIXI.WebGLFastSpriteBatch.prototype.begin = function(spriteBatch, renderSession)
  5072. {
  5073. this.renderSession = renderSession;
  5074. this.shader = this.renderSession.shaderManager.fastShader;
  5075. this.matrix = spriteBatch.worldTransform.toArray(true);
  5076. this.start();
  5077. };
  5078. PIXI.WebGLFastSpriteBatch.prototype.end = function()
  5079. {
  5080. this.flush();
  5081. };
  5082. PIXI.WebGLFastSpriteBatch.prototype.render = function(spriteBatch)
  5083. {
  5084. var children = spriteBatch.children;
  5085. var sprite = children[0];
  5086. // if the uvs have not updated then no point rendering just yet!
  5087. // check texture.
  5088. if(!sprite.texture._uvs)return;
  5089. this.currentBaseTexture = sprite.texture.baseTexture;
  5090. // check blend mode
  5091. if(sprite.blendMode !== this.currentBlendMode)
  5092. {
  5093. this.setBlendMode(sprite.blendMode);
  5094. }
  5095. for(var i=0,j= children.length; i<j; i++)
  5096. {
  5097. this.renderSprite(children[i]);
  5098. }
  5099. this.flush();
  5100. };
  5101. PIXI.WebGLFastSpriteBatch.prototype.renderSprite = function(sprite)
  5102. {
  5103. //sprite = children[i];
  5104. if(!sprite.visible)return;
  5105. // TODO trim??
  5106. if(sprite.texture.baseTexture !== this.currentBaseTexture)
  5107. {
  5108. this.flush();
  5109. this.currentBaseTexture = sprite.texture.baseTexture;
  5110. if(!sprite.texture._uvs)return;
  5111. }
  5112. var uvs, verticies = this.vertices, width, height, w0, w1, h0, h1, index;
  5113. uvs = sprite.texture._uvs;
  5114. width = sprite.texture.frame.width;
  5115. height = sprite.texture.frame.height;
  5116. if (sprite.texture.trim)
  5117. {
  5118. // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
  5119. var trim = sprite.texture.trim;
  5120. w1 = trim.x - sprite.anchor.x * trim.width;
  5121. w0 = w1 + sprite.texture.frame.width;
  5122. h1 = trim.y - sprite.anchor.y * trim.height;
  5123. h0 = h1 + sprite.texture.frame.height;
  5124. }
  5125. else
  5126. {
  5127. w0 = (sprite.texture.frame.width ) * (1-sprite.anchor.x);
  5128. w1 = (sprite.texture.frame.width ) * -sprite.anchor.x;
  5129. h0 = sprite.texture.frame.height * (1-sprite.anchor.y);
  5130. h1 = sprite.texture.frame.height * -sprite.anchor.y;
  5131. }
  5132. index = this.currentBatchSize * 4 * this.vertSize;
  5133. // xy
  5134. verticies[index++] = w1;
  5135. verticies[index++] = h1;
  5136. verticies[index++] = sprite.position.x;
  5137. verticies[index++] = sprite.position.y;
  5138. //scale
  5139. verticies[index++] = sprite.scale.x;
  5140. verticies[index++] = sprite.scale.y;
  5141. //rotation
  5142. verticies[index++] = sprite.rotation;
  5143. // uv
  5144. verticies[index++] = uvs.x0;
  5145. verticies[index++] = uvs.y1;
  5146. // color
  5147. verticies[index++] = sprite.alpha;
  5148. // xy
  5149. verticies[index++] = w0;
  5150. verticies[index++] = h1;
  5151. verticies[index++] = sprite.position.x;
  5152. verticies[index++] = sprite.position.y;
  5153. //scale
  5154. verticies[index++] = sprite.scale.x;
  5155. verticies[index++] = sprite.scale.y;
  5156. //rotation
  5157. verticies[index++] = sprite.rotation;
  5158. // uv
  5159. verticies[index++] = uvs.x1;
  5160. verticies[index++] = uvs.y1;
  5161. // color
  5162. verticies[index++] = sprite.alpha;
  5163. // xy
  5164. verticies[index++] = w0;
  5165. verticies[index++] = h0;
  5166. verticies[index++] = sprite.position.x;
  5167. verticies[index++] = sprite.position.y;
  5168. //scale
  5169. verticies[index++] = sprite.scale.x;
  5170. verticies[index++] = sprite.scale.y;
  5171. //rotation
  5172. verticies[index++] = sprite.rotation;
  5173. // uv
  5174. verticies[index++] = uvs.x2;
  5175. verticies[index++] = uvs.y2;
  5176. // color
  5177. verticies[index++] = sprite.alpha;
  5178. // xy
  5179. verticies[index++] = w1;
  5180. verticies[index++] = h0;
  5181. verticies[index++] = sprite.position.x;
  5182. verticies[index++] = sprite.position.y;
  5183. //scale
  5184. verticies[index++] = sprite.scale.x;
  5185. verticies[index++] = sprite.scale.y;
  5186. //rotation
  5187. verticies[index++] = sprite.rotation;
  5188. // uv
  5189. verticies[index++] = uvs.x3;
  5190. verticies[index++] = uvs.y3;
  5191. // color
  5192. verticies[index++] = sprite.alpha;
  5193. // increment the batchs
  5194. this.currentBatchSize++;
  5195. if(this.currentBatchSize >= this.size)
  5196. {
  5197. this.flush();
  5198. }
  5199. };
  5200. PIXI.WebGLFastSpriteBatch.prototype.flush = function()
  5201. {
  5202. // If the batch is length 0 then return as there is nothing to draw
  5203. if (this.currentBatchSize===0)return;
  5204. var gl = this.gl;
  5205. // bind the current texture
  5206. if(!this.currentBaseTexture._glTextures[gl.id])PIXI.createWebGLTexture(this.currentBaseTexture, gl);
  5207. gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]);// || PIXI.createWebGLTexture(this.currentBaseTexture, gl));
  5208. // upload the verts to the buffer
  5209. if(this.currentBatchSize > ( this.size * 0.5 ) )
  5210. {
  5211. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
  5212. }
  5213. else
  5214. {
  5215. var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
  5216. gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
  5217. }
  5218. // now draw those suckas!
  5219. gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0);
  5220. // then reset the batch!
  5221. this.currentBatchSize = 0;
  5222. // increment the draw count
  5223. this.renderSession.drawCount++;
  5224. };
  5225. PIXI.WebGLFastSpriteBatch.prototype.stop = function()
  5226. {
  5227. this.flush();
  5228. };
  5229. PIXI.WebGLFastSpriteBatch.prototype.start = function()
  5230. {
  5231. var gl = this.gl;
  5232. // bind the main texture
  5233. gl.activeTexture(gl.TEXTURE0);
  5234. // bind the buffers
  5235. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5236. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  5237. // set the projection
  5238. var projection = this.renderSession.projection;
  5239. gl.uniform2f(this.shader.projectionVector, projection.x, projection.y);
  5240. // set the matrix
  5241. gl.uniformMatrix3fv(this.shader.uMatrix, false, this.matrix);
  5242. // set the pointers
  5243. var stride = this.vertSize * 4;
  5244. gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
  5245. gl.vertexAttribPointer(this.shader.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4);
  5246. gl.vertexAttribPointer(this.shader.aScale, 2, gl.FLOAT, false, stride, 4 * 4);
  5247. gl.vertexAttribPointer(this.shader.aRotation, 1, gl.FLOAT, false, stride, 6 * 4);
  5248. gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4);
  5249. gl.vertexAttribPointer(this.shader.colorAttribute, 1, gl.FLOAT, false, stride, 9 * 4);
  5250. // set the blend mode..
  5251. if(this.currentBlendMode !== PIXI.blendModes.NORMAL)
  5252. {
  5253. this.setBlendMode(PIXI.blendModes.NORMAL);
  5254. }
  5255. };
  5256. PIXI.WebGLFastSpriteBatch.prototype.setBlendMode = function(blendMode)
  5257. {
  5258. this.flush();
  5259. this.currentBlendMode = blendMode;
  5260. var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
  5261. this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
  5262. };
  5263. /**
  5264. * @author Mat Groves http://matgroves.com/ @Doormat23
  5265. */
  5266. /**
  5267. * @class WebGLFilterManager
  5268. * @constructor
  5269. * @param gl {WebGLContext} the current WebGL drawing context
  5270. * @param transparent {Boolean} Whether or not the drawing context should be transparent
  5271. * @private
  5272. */
  5273. PIXI.WebGLFilterManager = function(gl, transparent)
  5274. {
  5275. this.transparent = transparent;
  5276. this.filterStack = [];
  5277. this.offsetX = 0;
  5278. this.offsetY = 0;
  5279. this.setContext(gl);
  5280. };
  5281. // API
  5282. /**
  5283. * Initialises the context and the properties
  5284. * @method setContext
  5285. * @param gl {WebGLContext} the current WebGL drawing context
  5286. */
  5287. PIXI.WebGLFilterManager.prototype.setContext = function(gl)
  5288. {
  5289. this.gl = gl;
  5290. this.texturePool = [];
  5291. this.initShaderBuffers();
  5292. };
  5293. /**
  5294. *
  5295. * @method begin
  5296. * @param renderSession {RenderSession}
  5297. * @param buffer {ArrayBuffer}
  5298. */
  5299. PIXI.WebGLFilterManager.prototype.begin = function(renderSession, buffer)
  5300. {
  5301. this.renderSession = renderSession;
  5302. this.defaultShader = renderSession.shaderManager.defaultShader;
  5303. var projection = this.renderSession.projection;
  5304. // console.log(this.width)
  5305. this.width = projection.x * 2;
  5306. this.height = -projection.y * 2;
  5307. this.buffer = buffer;
  5308. };
  5309. /**
  5310. * Applies the filter and adds it to the current filter stack
  5311. * @method pushFilter
  5312. * @param filterBlock {Object} the filter that will be pushed to the current filter stack
  5313. */
  5314. PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock)
  5315. {
  5316. var gl = this.gl;
  5317. var projection = this.renderSession.projection;
  5318. var offset = this.renderSession.offset;
  5319. filterBlock._filterArea = filterBlock.target.filterArea || filterBlock.target.getBounds();
  5320. // filter program
  5321. // OPTIMISATION - the first filter is free if its a simple color change?
  5322. this.filterStack.push(filterBlock);
  5323. var filter = filterBlock.filterPasses[0];
  5324. this.offsetX += filterBlock._filterArea.x;
  5325. this.offsetY += filterBlock._filterArea.y;
  5326. var texture = this.texturePool.pop();
  5327. if(!texture)
  5328. {
  5329. texture = new PIXI.FilterTexture(this.gl, this.width, this.height);
  5330. }
  5331. else
  5332. {
  5333. texture.resize(this.width, this.height);
  5334. }
  5335. gl.bindTexture(gl.TEXTURE_2D, texture.texture);
  5336. var filterArea = filterBlock._filterArea;// filterBlock.target.getBounds();///filterBlock.target.filterArea;
  5337. var padidng = filter.padding;
  5338. filterArea.x -= padidng;
  5339. filterArea.y -= padidng;
  5340. filterArea.width += padidng * 2;
  5341. filterArea.height += padidng * 2;
  5342. // cap filter to screen size..
  5343. if(filterArea.x < 0)filterArea.x = 0;
  5344. if(filterArea.width > this.width)filterArea.width = this.width;
  5345. if(filterArea.y < 0)filterArea.y = 0;
  5346. if(filterArea.height > this.height)filterArea.height = this.height;
  5347. //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  5348. gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer);
  5349. // set view port
  5350. gl.viewport(0, 0, filterArea.width, filterArea.height);
  5351. projection.x = filterArea.width/2;
  5352. projection.y = -filterArea.height/2;
  5353. offset.x = -filterArea.x;
  5354. offset.y = -filterArea.y;
  5355. // update projection
  5356. gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2);
  5357. gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y);
  5358. gl.colorMask(true, true, true, true);
  5359. gl.clearColor(0,0,0, 0);
  5360. gl.clear(gl.COLOR_BUFFER_BIT);
  5361. filterBlock._glFilterTexture = texture;
  5362. };
  5363. /**
  5364. * Removes the last filter from the filter stack and doesn't return it
  5365. * @method popFilter
  5366. */
  5367. PIXI.WebGLFilterManager.prototype.popFilter = function()
  5368. {
  5369. var gl = this.gl;
  5370. var filterBlock = this.filterStack.pop();
  5371. var filterArea = filterBlock._filterArea;
  5372. var texture = filterBlock._glFilterTexture;
  5373. var projection = this.renderSession.projection;
  5374. var offset = this.renderSession.offset;
  5375. if(filterBlock.filterPasses.length > 1)
  5376. {
  5377. gl.viewport(0, 0, filterArea.width, filterArea.height);
  5378. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5379. this.vertexArray[0] = 0;
  5380. this.vertexArray[1] = filterArea.height;
  5381. this.vertexArray[2] = filterArea.width;
  5382. this.vertexArray[3] = filterArea.height;
  5383. this.vertexArray[4] = 0;
  5384. this.vertexArray[5] = 0;
  5385. this.vertexArray[6] = filterArea.width;
  5386. this.vertexArray[7] = 0;
  5387. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);
  5388. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  5389. // now set the uvs..
  5390. this.uvArray[2] = filterArea.width/this.width;
  5391. this.uvArray[5] = filterArea.height/this.height;
  5392. this.uvArray[6] = filterArea.width/this.width;
  5393. this.uvArray[7] = filterArea.height/this.height;
  5394. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);
  5395. var inputTexture = texture;
  5396. var outputTexture = this.texturePool.pop();
  5397. if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.gl, this.width, this.height);
  5398. outputTexture.resize(this.width, this.height);
  5399. // need to clear this FBO as it may have some left over elements from a previous filter.
  5400. gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );
  5401. gl.clear(gl.COLOR_BUFFER_BIT);
  5402. gl.disable(gl.BLEND);
  5403. for (var i = 0; i < filterBlock.filterPasses.length-1; i++)
  5404. {
  5405. var filterPass = filterBlock.filterPasses[i];
  5406. gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );
  5407. // set texture
  5408. gl.activeTexture(gl.TEXTURE0);
  5409. gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture);
  5410. // draw texture..
  5411. //filterPass.applyFilterPass(filterArea.width, filterArea.height);
  5412. this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height);
  5413. // swap the textures..
  5414. var temp = inputTexture;
  5415. inputTexture = outputTexture;
  5416. outputTexture = temp;
  5417. }
  5418. gl.enable(gl.BLEND);
  5419. texture = inputTexture;
  5420. this.texturePool.push(outputTexture);
  5421. }
  5422. var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1];
  5423. this.offsetX -= filterArea.x;
  5424. this.offsetY -= filterArea.y;
  5425. var sizeX = this.width;
  5426. var sizeY = this.height;
  5427. var offsetX = 0;
  5428. var offsetY = 0;
  5429. var buffer = this.buffer;
  5430. // time to render the filters texture to the previous scene
  5431. if(this.filterStack.length === 0)
  5432. {
  5433. gl.colorMask(true, true, true, true);//this.transparent);
  5434. }
  5435. else
  5436. {
  5437. var currentFilter = this.filterStack[this.filterStack.length-1];
  5438. filterArea = currentFilter._filterArea;
  5439. sizeX = filterArea.width;
  5440. sizeY = filterArea.height;
  5441. offsetX = filterArea.x;
  5442. offsetY = filterArea.y;
  5443. buffer = currentFilter._glFilterTexture.frameBuffer;
  5444. }
  5445. // TODO need toremove thease global elements..
  5446. projection.x = sizeX/2;
  5447. projection.y = -sizeY/2;
  5448. offset.x = offsetX;
  5449. offset.y = offsetY;
  5450. filterArea = filterBlock._filterArea;
  5451. var x = filterArea.x-offsetX;
  5452. var y = filterArea.y-offsetY;
  5453. // update the buffers..
  5454. // make sure to flip the y!
  5455. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5456. this.vertexArray[0] = x;
  5457. this.vertexArray[1] = y + filterArea.height;
  5458. this.vertexArray[2] = x + filterArea.width;
  5459. this.vertexArray[3] = y + filterArea.height;
  5460. this.vertexArray[4] = x;
  5461. this.vertexArray[5] = y;
  5462. this.vertexArray[6] = x + filterArea.width;
  5463. this.vertexArray[7] = y;
  5464. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);
  5465. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  5466. this.uvArray[2] = filterArea.width/this.width;
  5467. this.uvArray[5] = filterArea.height/this.height;
  5468. this.uvArray[6] = filterArea.width/this.width;
  5469. this.uvArray[7] = filterArea.height/this.height;
  5470. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);
  5471. //console.log(this.vertexArray)
  5472. //console.log(this.uvArray)
  5473. //console.log(sizeX + " : " + sizeY)
  5474. gl.viewport(0, 0, sizeX, sizeY);
  5475. // bind the buffer
  5476. gl.bindFramebuffer(gl.FRAMEBUFFER, buffer );
  5477. // set the blend mode!
  5478. //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
  5479. // set texture
  5480. gl.activeTexture(gl.TEXTURE0);
  5481. gl.bindTexture(gl.TEXTURE_2D, texture.texture);
  5482. // apply!
  5483. this.applyFilterPass(filter, filterArea, sizeX, sizeY);
  5484. // now restore the regular shader..
  5485. gl.useProgram(this.defaultShader.program);
  5486. gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2);
  5487. gl.uniform2f(this.defaultShader.offsetVector, -offsetX, -offsetY);
  5488. // return the texture to the pool
  5489. this.texturePool.push(texture);
  5490. filterBlock._glFilterTexture = null;
  5491. };
  5492. /**
  5493. * Applies the filter to the specified area
  5494. * @method applyFilterPass
  5495. * @param filter {AbstractFilter} the filter that needs to be applied
  5496. * @param filterArea {texture} TODO - might need an update
  5497. * @param width {Number} the horizontal range of the filter
  5498. * @param height {Number} the vertical range of the filter
  5499. */
  5500. PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height)
  5501. {
  5502. // use program
  5503. var gl = this.gl;
  5504. var shader = filter.shaders[gl.id];
  5505. if(!shader)
  5506. {
  5507. shader = new PIXI.PixiShader(gl);
  5508. shader.fragmentSrc = filter.fragmentSrc;
  5509. shader.uniforms = filter.uniforms;
  5510. shader.init();
  5511. filter.shaders[gl.id] = shader;
  5512. }
  5513. // set the shader
  5514. gl.useProgram(shader.program);
  5515. gl.uniform2f(shader.projectionVector, width/2, -height/2);
  5516. gl.uniform2f(shader.offsetVector, 0,0);
  5517. if(filter.uniforms.dimensions)
  5518. {
  5519. filter.uniforms.dimensions.value[0] = this.width;//width;
  5520. filter.uniforms.dimensions.value[1] = this.height;//height;
  5521. filter.uniforms.dimensions.value[2] = this.vertexArray[0];
  5522. filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height;
  5523. }
  5524. // console.log(this.uvArray )
  5525. shader.syncUniforms();
  5526. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5527. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
  5528. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  5529. gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
  5530. gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
  5531. gl.vertexAttribPointer(shader.colorAttribute, 2, gl.FLOAT, false, 0, 0);
  5532. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  5533. // draw the filter...
  5534. gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  5535. this.renderSession.drawCount++;
  5536. };
  5537. /**
  5538. * Initialises the shader buffers
  5539. * @method initShaderBuffers
  5540. */
  5541. PIXI.WebGLFilterManager.prototype.initShaderBuffers = function()
  5542. {
  5543. var gl = this.gl;
  5544. // create some buffers
  5545. this.vertexBuffer = gl.createBuffer();
  5546. this.uvBuffer = gl.createBuffer();
  5547. this.colorBuffer = gl.createBuffer();
  5548. this.indexBuffer = gl.createBuffer();
  5549. // bind and upload the vertexs..
  5550. // keep a reference to the vertexFloatData..
  5551. this.vertexArray = new Float32Array([0.0, 0.0,
  5552. 1.0, 0.0,
  5553. 0.0, 1.0,
  5554. 1.0, 1.0]);
  5555. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  5556. gl.bufferData(
  5557. gl.ARRAY_BUFFER,
  5558. this.vertexArray,
  5559. gl.STATIC_DRAW);
  5560. // bind and upload the uv buffer
  5561. this.uvArray = new Float32Array([0.0, 0.0,
  5562. 1.0, 0.0,
  5563. 0.0, 1.0,
  5564. 1.0, 1.0]);
  5565. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  5566. gl.bufferData(
  5567. gl.ARRAY_BUFFER,
  5568. this.uvArray,
  5569. gl.STATIC_DRAW);
  5570. this.colorArray = new Float32Array([1.0, 0xFFFFFF,
  5571. 1.0, 0xFFFFFF,
  5572. 1.0, 0xFFFFFF,
  5573. 1.0, 0xFFFFFF]);
  5574. gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
  5575. gl.bufferData(
  5576. gl.ARRAY_BUFFER,
  5577. this.colorArray,
  5578. gl.STATIC_DRAW);
  5579. // bind and upload the index
  5580. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  5581. gl.bufferData(
  5582. gl.ELEMENT_ARRAY_BUFFER,
  5583. new Uint16Array([0, 1, 2, 1, 3, 2]),
  5584. gl.STATIC_DRAW);
  5585. };
  5586. /**
  5587. * Destroys the filter and removes it from the filter stack
  5588. * @method destroy
  5589. */
  5590. PIXI.WebGLFilterManager.prototype.destroy = function()
  5591. {
  5592. var gl = this.gl;
  5593. this.filterStack = null;
  5594. this.offsetX = 0;
  5595. this.offsetY = 0;
  5596. // destroy textures
  5597. for (var i = 0; i < this.texturePool.length; i++) {
  5598. this.texturePool.destroy();
  5599. }
  5600. this.texturePool = null;
  5601. //destroy buffers..
  5602. gl.deleteBuffer(this.vertexBuffer);
  5603. gl.deleteBuffer(this.uvBuffer);
  5604. gl.deleteBuffer(this.colorBuffer);
  5605. gl.deleteBuffer(this.indexBuffer);
  5606. };
  5607. /**
  5608. * @author Mat Groves http://matgroves.com/ @Doormat23
  5609. */
  5610. /**
  5611. * @class FilterTexture
  5612. * @constructor
  5613. * @param gl {WebGLContext} the current WebGL drawing context
  5614. * @param width {Number} the horizontal range of the filter
  5615. * @param height {Number} the vertical range of the filter
  5616. * @private
  5617. */
  5618. PIXI.FilterTexture = function(gl, width, height)
  5619. {
  5620. /**
  5621. * @property gl
  5622. * @type WebGLContext
  5623. */
  5624. this.gl = gl;
  5625. // next time to create a frame buffer and texture
  5626. this.frameBuffer = gl.createFramebuffer();
  5627. this.texture = gl.createTexture();
  5628. gl.bindTexture(gl.TEXTURE_2D, this.texture);
  5629. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  5630. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  5631. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  5632. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  5633. gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer );
  5634. gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer );
  5635. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);
  5636. this.resize(width, height);
  5637. };
  5638. /**
  5639. * Clears the filter texture
  5640. * @method clear
  5641. */
  5642. PIXI.FilterTexture.prototype.clear = function()
  5643. {
  5644. var gl = this.gl;
  5645. gl.clearColor(0,0,0, 0);
  5646. gl.clear(gl.COLOR_BUFFER_BIT);
  5647. };
  5648. /**
  5649. * Resizes the texture to the specified width and height
  5650. *
  5651. * @method resize
  5652. * @param width {Number} the new width of the texture
  5653. * @param height {Number} the new height of the texture
  5654. */
  5655. PIXI.FilterTexture.prototype.resize = function(width, height)
  5656. {
  5657. if(this.width === width && this.height === height) return;
  5658. this.width = width;
  5659. this.height = height;
  5660. var gl = this.gl;
  5661. gl.bindTexture(gl.TEXTURE_2D, this.texture);
  5662. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  5663. };
  5664. /**
  5665. * Destroys the filter texture
  5666. * @method destroy
  5667. */
  5668. PIXI.FilterTexture.prototype.destroy = function()
  5669. {
  5670. var gl = this.gl;
  5671. gl.deleteFramebuffer( this.frameBuffer );
  5672. gl.deleteTexture( this.texture );
  5673. this.frameBuffer = null;
  5674. this.texture = null;
  5675. };
  5676. /**
  5677. * @author Mat Groves
  5678. *
  5679. *
  5680. */
  5681. /**
  5682. * A set of functions used to handle masking
  5683. *
  5684. * @class CanvasMaskManager
  5685. */
  5686. PIXI.CanvasMaskManager = function()
  5687. {
  5688. };
  5689. /**
  5690. * This method adds it to the current stack of masks
  5691. *
  5692. * @method pushMask
  5693. * @param maskData the maskData that will be pushed
  5694. * @param context {Context2D} the 2d drawing method of the canvas
  5695. */
  5696. PIXI.CanvasMaskManager.prototype.pushMask = function(maskData, context)
  5697. {
  5698. context.save();
  5699. var cacheAlpha = maskData.alpha;
  5700. var transform = maskData.worldTransform;
  5701. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
  5702. PIXI.CanvasGraphics.renderGraphicsMask(maskData, context);
  5703. context.clip();
  5704. maskData.worldAlpha = cacheAlpha;
  5705. };
  5706. /**
  5707. * Restores the current drawing context to the state it was before the mask was applied
  5708. *
  5709. * @method popMask
  5710. * @param context {Context2D} the 2d drawing method of the canvas
  5711. */
  5712. PIXI.CanvasMaskManager.prototype.popMask = function(context)
  5713. {
  5714. context.restore();
  5715. };
  5716. /**
  5717. * @author Mat Groves
  5718. *
  5719. *
  5720. */
  5721. /**
  5722. * @class CanvasTinter
  5723. * @constructor
  5724. * @static
  5725. */
  5726. PIXI.CanvasTinter = function()
  5727. {
  5728. /// this.textureCach
  5729. };
  5730. //PIXI.CanvasTinter.cachTint = true;
  5731. /**
  5732. * Basically this method just needs a sprite and a color and tints the sprite
  5733. * with the given color
  5734. *
  5735. * @method getTintedTexture
  5736. * @param sprite {Sprite} the sprite to tint
  5737. * @param color {Number} the color to use to tint the sprite with
  5738. */
  5739. PIXI.CanvasTinter.getTintedTexture = function(sprite, color)
  5740. {
  5741. var texture = sprite.texture;
  5742. color = PIXI.CanvasTinter.roundColor(color);
  5743. var stringColor = "#" + ("00000" + ( color | 0).toString(16)).substr(-6);
  5744. texture.tintCache = texture.tintCache || {};
  5745. if(texture.tintCache[stringColor]) return texture.tintCache[stringColor];
  5746. // clone texture..
  5747. var canvas = PIXI.CanvasTinter.canvas || document.createElement("canvas");
  5748. //PIXI.CanvasTinter.tintWithPerPixel(texture, stringColor, canvas);
  5749. PIXI.CanvasTinter.tintMethod(texture, color, canvas);
  5750. if(PIXI.CanvasTinter.convertTintToImage)
  5751. {
  5752. // is this better?
  5753. var tintImage = new Image();
  5754. tintImage.src = canvas.toDataURL();
  5755. texture.tintCache[stringColor] = tintImage;
  5756. }
  5757. else
  5758. {
  5759. texture.tintCache[stringColor] = canvas;
  5760. // if we are not converting the texture to an image then we need to lose the reference to the canvas
  5761. PIXI.CanvasTinter.canvas = null;
  5762. }
  5763. return canvas;
  5764. };
  5765. /**
  5766. * Tint a texture using the "multiply" operation
  5767. * @method tintWithMultiply
  5768. * @param texture {texture} the texture to tint
  5769. * @param color {Number} the color to use to tint the sprite with
  5770. * @param canvas {HTMLCanvasElement} the current canvas
  5771. */
  5772. PIXI.CanvasTinter.tintWithMultiply = function(texture, color, canvas)
  5773. {
  5774. var context = canvas.getContext( "2d" );
  5775. var frame = texture.frame;
  5776. canvas.width = frame.width;
  5777. canvas.height = frame.height;
  5778. context.fillStyle = "#" + ("00000" + ( color | 0).toString(16)).substr(-6);
  5779. context.fillRect(0, 0, frame.width, frame.height);
  5780. context.globalCompositeOperation = "multiply";
  5781. context.drawImage(texture.baseTexture.source,
  5782. frame.x,
  5783. frame.y,
  5784. frame.width,
  5785. frame.height,
  5786. 0,
  5787. 0,
  5788. frame.width,
  5789. frame.height);
  5790. context.globalCompositeOperation = "destination-atop";
  5791. context.drawImage(texture.baseTexture.source,
  5792. frame.x,
  5793. frame.y,
  5794. frame.width,
  5795. frame.height,
  5796. 0,
  5797. 0,
  5798. frame.width,
  5799. frame.height);
  5800. };
  5801. /**
  5802. * Tint a texture using the "overlay" operation
  5803. * @method tintWithOverlay
  5804. * @param texture {texture} the texture to tint
  5805. * @param color {Number} the color to use to tint the sprite with
  5806. * @param canvas {HTMLCanvasElement} the current canvas
  5807. */
  5808. PIXI.CanvasTinter.tintWithOverlay = function(texture, color, canvas)
  5809. {
  5810. var context = canvas.getContext( "2d" );
  5811. var frame = texture.frame;
  5812. canvas.width = frame.width;
  5813. canvas.height = frame.height;
  5814. context.globalCompositeOperation = "copy";
  5815. context.fillStyle = "#" + ("00000" + ( color | 0).toString(16)).substr(-6);
  5816. context.fillRect(0, 0, frame.width, frame.height);
  5817. context.globalCompositeOperation = "destination-atop";
  5818. context.drawImage(texture.baseTexture.source,
  5819. frame.x,
  5820. frame.y,
  5821. frame.width,
  5822. frame.height,
  5823. 0,
  5824. 0,
  5825. frame.width,
  5826. frame.height);
  5827. //context.globalCompositeOperation = "copy";
  5828. };
  5829. /**
  5830. * Tint a texture pixel per pixel
  5831. * @method tintPerPixel
  5832. * @param texture {texture} the texture to tint
  5833. * @param color {Number} the color to use to tint the sprite with
  5834. * @param canvas {HTMLCanvasElement} the current canvas
  5835. */
  5836. PIXI.CanvasTinter.tintWithPerPixel = function(texture, color, canvas)
  5837. {
  5838. var context = canvas.getContext( "2d" );
  5839. var frame = texture.frame;
  5840. canvas.width = frame.width;
  5841. canvas.height = frame.height;
  5842. context.globalCompositeOperation = "copy";
  5843. context.drawImage(texture.baseTexture.source,
  5844. frame.x,
  5845. frame.y,
  5846. frame.width,
  5847. frame.height,
  5848. 0,
  5849. 0,
  5850. frame.width,
  5851. frame.height);
  5852. var rgbValues = PIXI.hex2rgb(color);
  5853. var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2];
  5854. var pixelData = context.getImageData(0, 0, frame.width, frame.height);
  5855. var pixels = pixelData.data;
  5856. for (var i = 0; i < pixels.length; i += 4)
  5857. {
  5858. pixels[i+0] *= r;
  5859. pixels[i+1] *= g;
  5860. pixels[i+2] *= b;
  5861. }
  5862. context.putImageData(pixelData, 0, 0);
  5863. };
  5864. /**
  5865. * Rounds the specified color according to the PIXI.CanvasTinter.cacheStepsPerColorChannel
  5866. * @method roundColor
  5867. * @param color {number} the color to round, should be a hex color
  5868. */
  5869. PIXI.CanvasTinter.roundColor = function(color)
  5870. {
  5871. var step = PIXI.CanvasTinter.cacheStepsPerColorChannel;
  5872. var rgbValues = PIXI.hex2rgb(color);
  5873. rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step);
  5874. rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step);
  5875. rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step);
  5876. return PIXI.rgb2hex(rgbValues);
  5877. };
  5878. /**
  5879. *
  5880. * Number of steps which will be used as a cap when rounding colors
  5881. *
  5882. * @property cacheStepsPerColorChannel
  5883. * @type Number
  5884. */
  5885. PIXI.CanvasTinter.cacheStepsPerColorChannel = 8;
  5886. /**
  5887. *
  5888. * Number of steps which will be used as a cap when rounding colors
  5889. *
  5890. * @property convertTintToImage
  5891. * @type Boolean
  5892. */
  5893. PIXI.CanvasTinter.convertTintToImage = false;
  5894. /**
  5895. * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method
  5896. *
  5897. * @property canUseMultiply
  5898. * @type Boolean
  5899. */
  5900. PIXI.CanvasTinter.canUseMultiply = PIXI.canUseNewCanvasBlendModes();
  5901. PIXI.CanvasTinter.tintMethod = PIXI.CanvasTinter.canUseMultiply ? PIXI.CanvasTinter.tintWithMultiply : PIXI.CanvasTinter.tintWithPerPixel;
  5902. /**
  5903. * @author Mat Groves http://matgroves.com/ @Doormat23
  5904. */
  5905. /**
  5906. * 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.
  5907. * Dont forget to add the view to your DOM or you will not see anything :)
  5908. *
  5909. * @class CanvasRenderer
  5910. * @constructor
  5911. * @param width=800 {Number} the width of the canvas view
  5912. * @param height=600 {Number} the height of the canvas view
  5913. * @param [view] {HTMLCanvasElement} the canvas to use as a view, optional
  5914. * @param [transparent=false] {Boolean} the transparency of the render view, default false
  5915. */
  5916. PIXI.CanvasRenderer = function(width, height, view, transparent)
  5917. {
  5918. PIXI.defaultRenderer = PIXI.defaultRenderer || this;
  5919. this.type = PIXI.CANVAS_RENDERER;
  5920. /**
  5921. * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.
  5922. * If the Stage is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color.
  5923. * If the Stage is transparent Pixi will use clearRect to clear the canvas every frame.
  5924. * 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.
  5925. *
  5926. * @property clearBeforeRender
  5927. * @type Boolean
  5928. * @default
  5929. */
  5930. this.clearBeforeRender = true;
  5931. /**
  5932. * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
  5933. * Handy for crisp pixel art and speed on legacy devices.
  5934. *
  5935. * @property roundPixels
  5936. * @type Boolean
  5937. * @default
  5938. */
  5939. this.roundPixels = false;
  5940. /**
  5941. * Whether the render view is transparent
  5942. *
  5943. * @property transparent
  5944. * @type Boolean
  5945. */
  5946. this.transparent = !!transparent;
  5947. if(!PIXI.blendModesCanvas)
  5948. {
  5949. PIXI.blendModesCanvas = [];
  5950. if(PIXI.canUseNewCanvasBlendModes())
  5951. {
  5952. PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over";
  5953. PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK???
  5954. PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply";
  5955. PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen";
  5956. PIXI.blendModesCanvas[PIXI.blendModes.OVERLAY] = "overlay";
  5957. PIXI.blendModesCanvas[PIXI.blendModes.DARKEN] = "darken";
  5958. PIXI.blendModesCanvas[PIXI.blendModes.LIGHTEN] = "lighten";
  5959. PIXI.blendModesCanvas[PIXI.blendModes.COLOR_DODGE] = "color-dodge";
  5960. PIXI.blendModesCanvas[PIXI.blendModes.COLOR_BURN] = "color-burn";
  5961. PIXI.blendModesCanvas[PIXI.blendModes.HARD_LIGHT] = "hard-light";
  5962. PIXI.blendModesCanvas[PIXI.blendModes.SOFT_LIGHT] = "soft-light";
  5963. PIXI.blendModesCanvas[PIXI.blendModes.DIFFERENCE] = "difference";
  5964. PIXI.blendModesCanvas[PIXI.blendModes.EXCLUSION] = "exclusion";
  5965. PIXI.blendModesCanvas[PIXI.blendModes.HUE] = "hue";
  5966. PIXI.blendModesCanvas[PIXI.blendModes.SATURATION] = "saturation";
  5967. PIXI.blendModesCanvas[PIXI.blendModes.COLOR] = "color";
  5968. PIXI.blendModesCanvas[PIXI.blendModes.LUMINOSITY] = "luminosity";
  5969. }
  5970. else
  5971. {
  5972. // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough"
  5973. PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over";
  5974. PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK???
  5975. PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over";
  5976. PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over";
  5977. PIXI.blendModesCanvas[PIXI.blendModes.OVERLAY] = "source-over";
  5978. PIXI.blendModesCanvas[PIXI.blendModes.DARKEN] = "source-over";
  5979. PIXI.blendModesCanvas[PIXI.blendModes.LIGHTEN] = "source-over";
  5980. PIXI.blendModesCanvas[PIXI.blendModes.COLOR_DODGE] = "source-over";
  5981. PIXI.blendModesCanvas[PIXI.blendModes.COLOR_BURN] = "source-over";
  5982. PIXI.blendModesCanvas[PIXI.blendModes.HARD_LIGHT] = "source-over";
  5983. PIXI.blendModesCanvas[PIXI.blendModes.SOFT_LIGHT] = "source-over";
  5984. PIXI.blendModesCanvas[PIXI.blendModes.DIFFERENCE] = "source-over";
  5985. PIXI.blendModesCanvas[PIXI.blendModes.EXCLUSION] = "source-over";
  5986. PIXI.blendModesCanvas[PIXI.blendModes.HUE] = "source-over";
  5987. PIXI.blendModesCanvas[PIXI.blendModes.SATURATION] = "source-over";
  5988. PIXI.blendModesCanvas[PIXI.blendModes.COLOR] = "source-over";
  5989. PIXI.blendModesCanvas[PIXI.blendModes.LUMINOSITY] = "source-over";
  5990. }
  5991. }
  5992. /**
  5993. * The width of the canvas view
  5994. *
  5995. * @property width
  5996. * @type Number
  5997. * @default 800
  5998. */
  5999. this.width = width || 800;
  6000. /**
  6001. * The height of the canvas view
  6002. *
  6003. * @property height
  6004. * @type Number
  6005. * @default 600
  6006. */
  6007. this.height = height || 600;
  6008. /**
  6009. * The canvas element that everything is drawn to
  6010. *
  6011. * @property view
  6012. * @type HTMLCanvasElement
  6013. */
  6014. this.view = view || document.createElement( "canvas" );
  6015. /**
  6016. * The canvas 2d context that everything is drawn with
  6017. * @property context
  6018. * @type HTMLCanvasElement 2d Context
  6019. */
  6020. this.context = this.view.getContext( "2d", { alpha: this.transparent } );
  6021. this.refresh = true;
  6022. // hack to enable some hardware acceleration!
  6023. //this.view.style["transform"] = "translatez(0)";
  6024. this.view.width = this.width;
  6025. this.view.height = this.height;
  6026. this.count = 0;
  6027. /**
  6028. * Instance of a PIXI.CanvasMaskManager, handles masking when using the canvas renderer
  6029. * @property CanvasMaskManager
  6030. * @type CanvasMaskManager
  6031. */
  6032. this.maskManager = new PIXI.CanvasMaskManager();
  6033. /**
  6034. * The render session is just a bunch of parameter used for rendering
  6035. * @property renderSession
  6036. * @type Object
  6037. */
  6038. this.renderSession = {
  6039. context: this.context,
  6040. maskManager: this.maskManager,
  6041. scaleMode: null,
  6042. smoothProperty: null
  6043. };
  6044. if("imageSmoothingEnabled" in this.context)
  6045. this.renderSession.smoothProperty = "imageSmoothingEnabled";
  6046. else if("webkitImageSmoothingEnabled" in this.context)
  6047. this.renderSession.smoothProperty = "webkitImageSmoothingEnabled";
  6048. else if("mozImageSmoothingEnabled" in this.context)
  6049. this.renderSession.smoothProperty = "mozImageSmoothingEnabled";
  6050. else if("oImageSmoothingEnabled" in this.context)
  6051. this.renderSession.smoothProperty = "oImageSmoothingEnabled";
  6052. };
  6053. // constructor
  6054. PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer;
  6055. /**
  6056. * Renders the stage to its canvas view
  6057. *
  6058. * @method render
  6059. * @param stage {Stage} the Stage element to be rendered
  6060. */
  6061. PIXI.CanvasRenderer.prototype.render = function(stage)
  6062. {
  6063. // update textures if need be
  6064. PIXI.texturesToUpdate.length = 0;
  6065. PIXI.texturesToDestroy.length = 0;
  6066. stage.updateTransform();
  6067. this.context.setTransform(1,0,0,1,0,0);
  6068. this.context.globalAlpha = 1;
  6069. if (!this.transparent && this.clearBeforeRender)
  6070. {
  6071. this.context.fillStyle = stage.backgroundColorString;
  6072. this.context.fillRect(0, 0, this.width, this.height);
  6073. }
  6074. else if (this.transparent && this.clearBeforeRender)
  6075. {
  6076. this.context.clearRect(0, 0, this.width, this.height);
  6077. }
  6078. this.renderDisplayObject(stage);
  6079. // run interaction!
  6080. if(stage.interactive)
  6081. {
  6082. //need to add some events!
  6083. if(!stage._interactiveEventsAdded)
  6084. {
  6085. stage._interactiveEventsAdded = true;
  6086. stage.interactionManager.setTarget(this);
  6087. }
  6088. }
  6089. // remove frame updates..
  6090. if(PIXI.Texture.frameUpdates.length > 0)
  6091. {
  6092. PIXI.Texture.frameUpdates.length = 0;
  6093. }
  6094. };
  6095. /**
  6096. * Resizes the canvas view to the specified width and height
  6097. *
  6098. * @method resize
  6099. * @param width {Number} the new width of the canvas view
  6100. * @param height {Number} the new height of the canvas view
  6101. */
  6102. PIXI.CanvasRenderer.prototype.resize = function(width, height)
  6103. {
  6104. this.width = width;
  6105. this.height = height;
  6106. this.view.width = width;
  6107. this.view.height = height;
  6108. };
  6109. /**
  6110. * Renders a display object
  6111. *
  6112. * @method renderDisplayObject
  6113. * @param displayObject {DisplayObject} The displayObject to render
  6114. * @param context {Context2D} the context 2d method of the canvas
  6115. * @private
  6116. */
  6117. PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject, context)
  6118. {
  6119. // no longer recursive!
  6120. //var transform;
  6121. //var context = this.context;
  6122. this.renderSession.context = context || this.context;
  6123. displayObject._renderCanvas(this.renderSession);
  6124. };
  6125. /**
  6126. * Renders a flat strip
  6127. *
  6128. * @method renderStripFlat
  6129. * @param strip {Strip} The Strip to render
  6130. * @private
  6131. */
  6132. PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip)
  6133. {
  6134. var context = this.context;
  6135. var verticies = strip.verticies;
  6136. var length = verticies.length/2;
  6137. this.count++;
  6138. context.beginPath();
  6139. for (var i=1; i < length-2; i++)
  6140. {
  6141. // draw some triangles!
  6142. var index = i*2;
  6143. var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4];
  6144. var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5];
  6145. context.moveTo(x0, y0);
  6146. context.lineTo(x1, y1);
  6147. context.lineTo(x2, y2);
  6148. }
  6149. context.fillStyle = "#FF0000";
  6150. context.fill();
  6151. context.closePath();
  6152. };
  6153. /**
  6154. * Renders a strip
  6155. *
  6156. * @method renderStrip
  6157. * @param strip {Strip} The Strip to render
  6158. * @private
  6159. */
  6160. PIXI.CanvasRenderer.prototype.renderStrip = function(strip)
  6161. {
  6162. var context = this.context;
  6163. // draw triangles!!
  6164. var verticies = strip.verticies;
  6165. var uvs = strip.uvs;
  6166. var length = verticies.length/2;
  6167. this.count++;
  6168. for (var i = 1; i < length-2; i++)
  6169. {
  6170. // draw some triangles!
  6171. var index = i*2;
  6172. var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4];
  6173. var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5];
  6174. var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width;
  6175. var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height;
  6176. context.save();
  6177. context.beginPath();
  6178. context.moveTo(x0, y0);
  6179. context.lineTo(x1, y1);
  6180. context.lineTo(x2, y2);
  6181. context.closePath();
  6182. context.clip();
  6183. // Compute matrix transform
  6184. var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2;
  6185. var deltaA = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2;
  6186. var deltaB = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2;
  6187. var deltaC = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2;
  6188. var deltaD = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2;
  6189. var deltaE = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2;
  6190. var deltaF = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2;
  6191. context.transform(deltaA / delta, deltaD / delta,
  6192. deltaB / delta, deltaE / delta,
  6193. deltaC / delta, deltaF / delta);
  6194. context.drawImage(strip.texture.baseTexture.source, 0, 0);
  6195. context.restore();
  6196. }
  6197. };
  6198. /**
  6199. * Creates a Canvas element of the given size
  6200. *
  6201. * @method CanvasBuffer
  6202. * @param width {Number} the width for the newly created canvas
  6203. * @param height {Number} the height for the newly created canvas
  6204. * @static
  6205. * @private
  6206. */
  6207. PIXI.CanvasBuffer = function(width, height)
  6208. {
  6209. this.width = width;
  6210. this.height = height;
  6211. this.canvas = document.createElement( "canvas" );
  6212. this.context = this.canvas.getContext( "2d" );
  6213. this.canvas.width = width;
  6214. this.canvas.height = height;
  6215. };
  6216. /**
  6217. * Clears the canvas that was created by the CanvasBuffer class
  6218. *
  6219. * @method clear
  6220. * @private
  6221. */
  6222. PIXI.CanvasBuffer.prototype.clear = function()
  6223. {
  6224. this.context.clearRect(0,0, this.width, this.height);
  6225. };
  6226. /**
  6227. * Resizes the canvas that was created by the CanvasBuffer class to the specified width and height
  6228. *
  6229. * @method resize
  6230. * @param width {Number} the new width of the canvas
  6231. * @param height {Number} the new height of the canvas
  6232. * @private
  6233. */
  6234. PIXI.CanvasBuffer.prototype.resize = function(width, height)
  6235. {
  6236. this.width = this.canvas.width = width;
  6237. this.height = this.canvas.height = height;
  6238. };
  6239. /**
  6240. * @author Mat Groves http://matgroves.com/ @Doormat23
  6241. */
  6242. /**
  6243. * A set of functions used by the canvas renderer to draw the primitive graphics data
  6244. *
  6245. * @class CanvasGraphics
  6246. */
  6247. PIXI.CanvasGraphics = function()
  6248. {
  6249. };
  6250. /*
  6251. * Renders the graphics object
  6252. *
  6253. * @static
  6254. * @private
  6255. * @method renderGraphics
  6256. * @param graphics {Graphics} the actual graphics object to render
  6257. * @param context {Context2D} the 2d drawing method of the canvas
  6258. */
  6259. PIXI.CanvasGraphics.renderGraphics = function(graphics, context)
  6260. {
  6261. var worldAlpha = graphics.worldAlpha;
  6262. var color = '';
  6263. for (var i = 0; i < graphics.graphicsData.length; i++)
  6264. {
  6265. var data = graphics.graphicsData[i];
  6266. var points = data.points;
  6267. context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6);
  6268. context.lineWidth = data.lineWidth;
  6269. if(data.type === PIXI.Graphics.POLY)
  6270. {
  6271. context.beginPath();
  6272. context.moveTo(points[0], points[1]);
  6273. for (var j=1; j < points.length/2; j++)
  6274. {
  6275. context.lineTo(points[j * 2], points[j * 2 + 1]);
  6276. }
  6277. // if the first and last point are the same close the path - much neater :)
  6278. if(points[0] === points[points.length-2] && points[1] === points[points.length-1])
  6279. {
  6280. context.closePath();
  6281. }
  6282. if(data.fill)
  6283. {
  6284. context.globalAlpha = data.fillAlpha * worldAlpha;
  6285. context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6);
  6286. context.fill();
  6287. }
  6288. if(data.lineWidth)
  6289. {
  6290. context.globalAlpha = data.lineAlpha * worldAlpha;
  6291. context.stroke();
  6292. }
  6293. }
  6294. else if(data.type === PIXI.Graphics.RECT)
  6295. {
  6296. if(data.fillColor || data.fillColor === 0)
  6297. {
  6298. context.globalAlpha = data.fillAlpha * worldAlpha;
  6299. context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6);
  6300. context.fillRect(points[0], points[1], points[2], points[3]);
  6301. }
  6302. if(data.lineWidth)
  6303. {
  6304. context.globalAlpha = data.lineAlpha * worldAlpha;
  6305. context.strokeRect(points[0], points[1], points[2], points[3]);
  6306. }
  6307. }
  6308. else if(data.type === PIXI.Graphics.CIRC)
  6309. {
  6310. // TODO - need to be Undefined!
  6311. context.beginPath();
  6312. context.arc(points[0], points[1], points[2],0,2*Math.PI);
  6313. context.closePath();
  6314. if(data.fill)
  6315. {
  6316. context.globalAlpha = data.fillAlpha * worldAlpha;
  6317. context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6);
  6318. context.fill();
  6319. }
  6320. if(data.lineWidth)
  6321. {
  6322. context.globalAlpha = data.lineAlpha * worldAlpha;
  6323. context.stroke();
  6324. }
  6325. }
  6326. else if(data.type === PIXI.Graphics.ELIP)
  6327. {
  6328. // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  6329. var ellipseData = data.points;
  6330. var w = ellipseData[2] * 2;
  6331. var h = ellipseData[3] * 2;
  6332. var x = ellipseData[0] - w/2;
  6333. var y = ellipseData[1] - h/2;
  6334. context.beginPath();
  6335. var kappa = 0.5522848,
  6336. ox = (w / 2) * kappa, // control point offset horizontal
  6337. oy = (h / 2) * kappa, // control point offset vertical
  6338. xe = x + w, // x-end
  6339. ye = y + h, // y-end
  6340. xm = x + w / 2, // x-middle
  6341. ym = y + h / 2; // y-middle
  6342. context.moveTo(x, ym);
  6343. context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  6344. context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  6345. context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  6346. context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  6347. context.closePath();
  6348. if(data.fill)
  6349. {
  6350. context.globalAlpha = data.fillAlpha * worldAlpha;
  6351. context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6);
  6352. context.fill();
  6353. }
  6354. if(data.lineWidth)
  6355. {
  6356. context.globalAlpha = data.lineAlpha * worldAlpha;
  6357. context.stroke();
  6358. }
  6359. }
  6360. }
  6361. };
  6362. /*
  6363. * Renders a graphics mask
  6364. *
  6365. * @static
  6366. * @private
  6367. * @method renderGraphicsMask
  6368. * @param graphics {Graphics} the graphics which will be used as a mask
  6369. * @param context {Context2D} the context 2d method of the canvas
  6370. */
  6371. PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context)
  6372. {
  6373. var len = graphics.graphicsData.length;
  6374. if(len === 0) return;
  6375. if(len > 1)
  6376. {
  6377. len = 1;
  6378. window.console.log('Pixi.js warning: masks in canvas can only mask using the first path in the graphics object');
  6379. }
  6380. for (var i = 0; i < 1; i++)
  6381. {
  6382. var data = graphics.graphicsData[i];
  6383. var points = data.points;
  6384. if(data.type === PIXI.Graphics.POLY)
  6385. {
  6386. context.beginPath();
  6387. context.moveTo(points[0], points[1]);
  6388. for (var j=1; j < points.length/2; j++)
  6389. {
  6390. context.lineTo(points[j * 2], points[j * 2 + 1]);
  6391. }
  6392. // if the first and last point are the same close the path - much neater :)
  6393. if(points[0] === points[points.length-2] && points[1] === points[points.length-1])
  6394. {
  6395. context.closePath();
  6396. }
  6397. }
  6398. else if(data.type === PIXI.Graphics.RECT)
  6399. {
  6400. context.beginPath();
  6401. context.rect(points[0], points[1], points[2], points[3]);
  6402. context.closePath();
  6403. }
  6404. else if(data.type === PIXI.Graphics.CIRC)
  6405. {
  6406. // TODO - need to be Undefined!
  6407. context.beginPath();
  6408. context.arc(points[0], points[1], points[2],0,2*Math.PI);
  6409. context.closePath();
  6410. }
  6411. else if(data.type === PIXI.Graphics.ELIP)
  6412. {
  6413. // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  6414. var ellipseData = data.points;
  6415. var w = ellipseData[2] * 2;
  6416. var h = ellipseData[3] * 2;
  6417. var x = ellipseData[0] - w/2;
  6418. var y = ellipseData[1] - h/2;
  6419. context.beginPath();
  6420. var kappa = 0.5522848,
  6421. ox = (w / 2) * kappa, // control point offset horizontal
  6422. oy = (h / 2) * kappa, // control point offset vertical
  6423. xe = x + w, // x-end
  6424. ye = y + h, // y-end
  6425. xm = x + w / 2, // x-middle
  6426. ym = y + h / 2; // y-middle
  6427. context.moveTo(x, ym);
  6428. context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  6429. context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  6430. context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  6431. context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  6432. context.closePath();
  6433. }
  6434. }
  6435. };
  6436. /**
  6437. * @author Mat Groves http://matgroves.com/ @Doormat23
  6438. */
  6439. /**
  6440. * The Graphics class contains a set of methods that you can use to create primitive shapes and lines.
  6441. * It is important to know that with the webGL renderer only simple polygons can be filled at this stage
  6442. * Complex polygons will not be filled. Heres an example of a complex polygon: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png
  6443. *
  6444. * @class Graphics
  6445. * @extends DisplayObjectContainer
  6446. * @constructor
  6447. */
  6448. PIXI.Graphics = function()
  6449. {
  6450. PIXI.DisplayObjectContainer.call( this );
  6451. this.renderable = true;
  6452. /**
  6453. * The alpha of the fill of this graphics object
  6454. *
  6455. * @property fillAlpha
  6456. * @type Number
  6457. */
  6458. this.fillAlpha = 1;
  6459. /**
  6460. * The width of any lines drawn
  6461. *
  6462. * @property lineWidth
  6463. * @type Number
  6464. */
  6465. this.lineWidth = 0;
  6466. /**
  6467. * The color of any lines drawn
  6468. *
  6469. * @property lineColor
  6470. * @type String
  6471. */
  6472. this.lineColor = "black";
  6473. /**
  6474. * Graphics data
  6475. *
  6476. * @property graphicsData
  6477. * @type Array
  6478. * @private
  6479. */
  6480. this.graphicsData = [];
  6481. /**
  6482. * The tint applied to the graphic shape. This is a hex value
  6483. *
  6484. * @property tint
  6485. * @type Number
  6486. * @default 0xFFFFFF
  6487. */
  6488. this.tint = 0xFFFFFF;// * Math.random();
  6489. /**
  6490. * The blend mode to be applied to the graphic shape
  6491. *
  6492. * @property blendMode
  6493. * @type Number
  6494. * @default PIXI.blendModes.NORMAL;
  6495. */
  6496. this.blendMode = PIXI.blendModes.NORMAL;
  6497. /**
  6498. * Current path
  6499. *
  6500. * @property currentPath
  6501. * @type Object
  6502. * @private
  6503. */
  6504. this.currentPath = {points:[]};
  6505. /**
  6506. * Array containing some WebGL-related properties used by the WebGL renderer
  6507. *
  6508. * @property _webGL
  6509. * @type Array
  6510. * @private
  6511. */
  6512. this._webGL = [];
  6513. /**
  6514. * Whether this shape is being used as a mask
  6515. *
  6516. * @property isMask
  6517. * @type isMask
  6518. */
  6519. this.isMask = false;
  6520. /**
  6521. * The bounds of the graphic shape as rectangle object
  6522. *
  6523. * @property bounds
  6524. * @type Rectangle
  6525. */
  6526. this.bounds = null;
  6527. /**
  6528. * the bounds' padding used for bounds calculation
  6529. *
  6530. * @property bounds
  6531. * @type Number
  6532. */
  6533. this.boundsPadding = 10;
  6534. };
  6535. // constructor
  6536. PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
  6537. PIXI.Graphics.prototype.constructor = PIXI.Graphics;
  6538. /**
  6539. * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite.
  6540. * This is useful if your graphics element does not change often as it will speed up the rendering of the object
  6541. * It is also usful as the graphics object will always be antialiased because it will be rendered using canvas
  6542. * Not recommended if you are constanly redrawing the graphics element.
  6543. *
  6544. * @property cacheAsBitmap
  6545. * @default false
  6546. * @type Boolean
  6547. * @private
  6548. */
  6549. Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", {
  6550. get: function() {
  6551. return this._cacheAsBitmap;
  6552. },
  6553. set: function(value) {
  6554. this._cacheAsBitmap = value;
  6555. if(this._cacheAsBitmap)
  6556. {
  6557. this._generateCachedSprite();
  6558. }
  6559. else
  6560. {
  6561. this.destroyCachedSprite();
  6562. this.dirty = true;
  6563. }
  6564. }
  6565. });
  6566. /**
  6567. * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method.
  6568. *
  6569. * @method lineStyle
  6570. * @param lineWidth {Number} width of the line to draw, will update the object's stored style
  6571. * @param color {Number} color of the line to draw, will update the object's stored style
  6572. * @param alpha {Number} alpha of the line to draw, will update the object's stored style
  6573. */
  6574. PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha)
  6575. {
  6576. if (!this.currentPath.points.length) this.graphicsData.pop();
  6577. this.lineWidth = lineWidth || 0;
  6578. this.lineColor = color || 0;
  6579. this.lineAlpha = (arguments.length < 3) ? 1 : alpha;
  6580. this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
  6581. fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY};
  6582. this.graphicsData.push(this.currentPath);
  6583. return this;
  6584. };
  6585. /**
  6586. * Moves the current drawing position to (x, y).
  6587. *
  6588. * @method moveTo
  6589. * @param x {Number} the X coordinate to move to
  6590. * @param y {Number} the Y coordinate to move to
  6591. */
  6592. PIXI.Graphics.prototype.moveTo = function(x, y)
  6593. {
  6594. if (!this.currentPath.points.length) this.graphicsData.pop();
  6595. this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
  6596. fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY};
  6597. this.currentPath.points.push(x, y);
  6598. this.graphicsData.push(this.currentPath);
  6599. return this;
  6600. };
  6601. /**
  6602. * Draws a line using the current line style from the current drawing position to (x, y);
  6603. * the current drawing position is then set to (x, y).
  6604. *
  6605. * @method lineTo
  6606. * @param x {Number} the X coordinate to draw to
  6607. * @param y {Number} the Y coordinate to draw to
  6608. */
  6609. PIXI.Graphics.prototype.lineTo = function(x, y)
  6610. {
  6611. this.currentPath.points.push(x, y);
  6612. this.dirty = true;
  6613. return this;
  6614. };
  6615. /**
  6616. * Specifies a simple one-color fill that subsequent calls to other Graphics methods
  6617. * (such as lineTo() or drawCircle()) use when drawing.
  6618. *
  6619. * @method beginFill
  6620. * @param color {Number} the color of the fill
  6621. * @param alpha {Number} the alpha of the fill
  6622. */
  6623. PIXI.Graphics.prototype.beginFill = function(color, alpha)
  6624. {
  6625. this.filling = true;
  6626. this.fillColor = color || 0;
  6627. this.fillAlpha = (arguments.length < 2) ? 1 : alpha;
  6628. return this;
  6629. };
  6630. /**
  6631. * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method.
  6632. *
  6633. * @method endFill
  6634. */
  6635. PIXI.Graphics.prototype.endFill = function()
  6636. {
  6637. this.filling = false;
  6638. this.fillColor = null;
  6639. this.fillAlpha = 1;
  6640. return this;
  6641. };
  6642. /**
  6643. * @method drawRect
  6644. *
  6645. * @param x {Number} The X coord of the top-left of the rectangle
  6646. * @param y {Number} The Y coord of the top-left of the rectangle
  6647. * @param width {Number} The width of the rectangle
  6648. * @param height {Number} The height of the rectangle
  6649. */
  6650. PIXI.Graphics.prototype.drawRect = function( x, y, width, height )
  6651. {
  6652. if (!this.currentPath.points.length) this.graphicsData.pop();
  6653. this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
  6654. fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling,
  6655. points:[x, y, width, height], type:PIXI.Graphics.RECT};
  6656. this.graphicsData.push(this.currentPath);
  6657. this.dirty = true;
  6658. return this;
  6659. };
  6660. /**
  6661. * Draws a circle.
  6662. *
  6663. * @method drawCircle
  6664. * @param x {Number} The X coordinate of the center of the circle
  6665. * @param y {Number} The Y coordinate of the center of the circle
  6666. * @param radius {Number} The radius of the circle
  6667. */
  6668. PIXI.Graphics.prototype.drawCircle = function( x, y, radius)
  6669. {
  6670. if (!this.currentPath.points.length) this.graphicsData.pop();
  6671. this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
  6672. fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling,
  6673. points:[x, y, radius, radius], type:PIXI.Graphics.CIRC};
  6674. this.graphicsData.push(this.currentPath);
  6675. this.dirty = true;
  6676. return this;
  6677. };
  6678. /**
  6679. * Draws an ellipse.
  6680. *
  6681. * @method drawEllipse
  6682. * @param x {Number} The X coordinate of the upper-left corner of the framing rectangle of this ellipse
  6683. * @param y {Number} The Y coordinate of the upper-left corner of the framing rectangle of this ellipse
  6684. * @param width {Number} The width of the ellipse
  6685. * @param height {Number} The height of the ellipse
  6686. */
  6687. PIXI.Graphics.prototype.drawEllipse = function( x, y, width, height)
  6688. {
  6689. if (!this.currentPath.points.length) this.graphicsData.pop();
  6690. this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
  6691. fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling,
  6692. points:[x, y, width, height], type:PIXI.Graphics.ELIP};
  6693. this.graphicsData.push(this.currentPath);
  6694. this.dirty = true;
  6695. return this;
  6696. };
  6697. /**
  6698. * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings.
  6699. *
  6700. * @method clear
  6701. */
  6702. PIXI.Graphics.prototype.clear = function()
  6703. {
  6704. this.lineWidth = 0;
  6705. this.filling = false;
  6706. this.dirty = true;
  6707. this.clearDirty = true;
  6708. this.graphicsData = [];
  6709. this.bounds = null; //new PIXI.Rectangle();
  6710. return this;
  6711. };
  6712. /**
  6713. * Useful function that returns a texture of the graphics object that can then be used to create sprites
  6714. * This can be quite useful if your geometry is complicated and needs to be reused multiple times.
  6715. *
  6716. * @method generateTexture
  6717. * @return {Texture} a texture of the graphics object
  6718. */
  6719. PIXI.Graphics.prototype.generateTexture = function()
  6720. {
  6721. var bounds = this.getBounds();
  6722. var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height);
  6723. var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
  6724. canvasBuffer.context.translate(-bounds.x,-bounds.y);
  6725. PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context);
  6726. return texture;
  6727. };
  6728. /**
  6729. * Renders the object using the WebGL renderer
  6730. *
  6731. * @method _renderWebGL
  6732. * @param renderSession {RenderSession}
  6733. * @private
  6734. */
  6735. PIXI.Graphics.prototype._renderWebGL = function(renderSession)
  6736. {
  6737. // if the sprite is not visible or the alpha is 0 then no need to render this element
  6738. if(this.visible === false || this.alpha === 0 || this.isMask === true)return;
  6739. if(this._cacheAsBitmap)
  6740. {
  6741. if(this.dirty)
  6742. {
  6743. this._generateCachedSprite();
  6744. // we will also need to update the texture on the gpu too!
  6745. PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl);
  6746. this.dirty = false;
  6747. }
  6748. this._cachedSprite.alpha = this.alpha;
  6749. PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession);
  6750. return;
  6751. }
  6752. else
  6753. {
  6754. renderSession.spriteBatch.stop();
  6755. if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession);
  6756. if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock);
  6757. // check blend mode
  6758. if(this.blendMode !== renderSession.spriteBatch.currentBlendMode)
  6759. {
  6760. renderSession.spriteBatch.currentBlendMode = this.blendMode;
  6761. var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode];
  6762. renderSession.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
  6763. }
  6764. PIXI.WebGLGraphics.renderGraphics(this, renderSession);
  6765. // only render if it has children!
  6766. if(this.children.length)
  6767. {
  6768. renderSession.spriteBatch.start();
  6769. // simple render children!
  6770. for(var i=0, j=this.children.length; i<j; i++)
  6771. {
  6772. this.children[i]._renderWebGL(renderSession);
  6773. }
  6774. renderSession.spriteBatch.stop();
  6775. }
  6776. if(this._filters)renderSession.filterManager.popFilter();
  6777. if(this._mask)renderSession.maskManager.popMask(renderSession);
  6778. renderSession.drawCount++;
  6779. renderSession.spriteBatch.start();
  6780. }
  6781. };
  6782. /**
  6783. * Renders the object using the Canvas renderer
  6784. *
  6785. * @method _renderCanvas
  6786. * @param renderSession {RenderSession}
  6787. * @private
  6788. */
  6789. PIXI.Graphics.prototype._renderCanvas = function(renderSession)
  6790. {
  6791. // if the sprite is not visible or the alpha is 0 then no need to render this element
  6792. if(this.visible === false || this.alpha === 0 || this.isMask === true)return;
  6793. var context = renderSession.context;
  6794. var transform = this.worldTransform;
  6795. if(this.blendMode !== renderSession.currentBlendMode)
  6796. {
  6797. renderSession.currentBlendMode = this.blendMode;
  6798. context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  6799. }
  6800. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty);
  6801. PIXI.CanvasGraphics.renderGraphics(this, context);
  6802. // simple render children!
  6803. for(var i=0, j=this.children.length; i<j; i++)
  6804. {
  6805. this.children[i]._renderCanvas(renderSession);
  6806. }
  6807. };
  6808. /**
  6809. * Retrieves the bounds of the graphic shape as a rectangle object
  6810. *
  6811. * @method getBounds
  6812. * @return {Rectangle} the rectangular bounding area
  6813. */
  6814. PIXI.Graphics.prototype.getBounds = function( matrix )
  6815. {
  6816. if(!this.bounds)this.updateBounds();
  6817. var w0 = this.bounds.x;
  6818. var w1 = this.bounds.width + this.bounds.x;
  6819. var h0 = this.bounds.y;
  6820. var h1 = this.bounds.height + this.bounds.y;
  6821. var worldTransform = matrix || this.worldTransform;
  6822. var a = worldTransform.a;
  6823. var b = worldTransform.c;
  6824. var c = worldTransform.b;
  6825. var d = worldTransform.d;
  6826. var tx = worldTransform.tx;
  6827. var ty = worldTransform.ty;
  6828. var x1 = a * w1 + c * h1 + tx;
  6829. var y1 = d * h1 + b * w1 + ty;
  6830. var x2 = a * w0 + c * h1 + tx;
  6831. var y2 = d * h1 + b * w0 + ty;
  6832. var x3 = a * w0 + c * h0 + tx;
  6833. var y3 = d * h0 + b * w0 + ty;
  6834. var x4 = a * w1 + c * h0 + tx;
  6835. var y4 = d * h0 + b * w1 + ty;
  6836. var maxX = -Infinity;
  6837. var maxY = -Infinity;
  6838. var minX = Infinity;
  6839. var minY = Infinity;
  6840. minX = x1 < minX ? x1 : minX;
  6841. minX = x2 < minX ? x2 : minX;
  6842. minX = x3 < minX ? x3 : minX;
  6843. minX = x4 < minX ? x4 : minX;
  6844. minY = y1 < minY ? y1 : minY;
  6845. minY = y2 < minY ? y2 : minY;
  6846. minY = y3 < minY ? y3 : minY;
  6847. minY = y4 < minY ? y4 : minY;
  6848. maxX = x1 > maxX ? x1 : maxX;
  6849. maxX = x2 > maxX ? x2 : maxX;
  6850. maxX = x3 > maxX ? x3 : maxX;
  6851. maxX = x4 > maxX ? x4 : maxX;
  6852. maxY = y1 > maxY ? y1 : maxY;
  6853. maxY = y2 > maxY ? y2 : maxY;
  6854. maxY = y3 > maxY ? y3 : maxY;
  6855. maxY = y4 > maxY ? y4 : maxY;
  6856. var bounds = this._bounds;
  6857. bounds.x = minX;
  6858. bounds.width = maxX - minX;
  6859. bounds.y = minY;
  6860. bounds.height = maxY - minY;
  6861. return bounds;
  6862. };
  6863. /**
  6864. * Update the bounds of the object
  6865. *
  6866. * @method updateBounds
  6867. */
  6868. PIXI.Graphics.prototype.updateBounds = function()
  6869. {
  6870. var minX = Infinity;
  6871. var maxX = -Infinity;
  6872. var minY = Infinity;
  6873. var maxY = -Infinity;
  6874. var points, x, y, w, h;
  6875. for (var i = 0; i < this.graphicsData.length; i++) {
  6876. var data = this.graphicsData[i];
  6877. var type = data.type;
  6878. var lineWidth = data.lineWidth;
  6879. points = data.points;
  6880. if(type === PIXI.Graphics.RECT)
  6881. {
  6882. x = points[0] - lineWidth/2;
  6883. y = points[1] - lineWidth/2;
  6884. w = points[2] + lineWidth;
  6885. h = points[3] + lineWidth;
  6886. minX = x < minX ? x : minX;
  6887. maxX = x + w > maxX ? x + w : maxX;
  6888. minY = y < minY ? x : minY;
  6889. maxY = y + h > maxY ? y + h : maxY;
  6890. }
  6891. else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP)
  6892. {
  6893. x = points[0];
  6894. y = points[1];
  6895. w = points[2] + lineWidth/2;
  6896. h = points[3] + lineWidth/2;
  6897. minX = x - w < minX ? x - w : minX;
  6898. maxX = x + w > maxX ? x + w : maxX;
  6899. minY = y - h < minY ? y - h : minY;
  6900. maxY = y + h > maxY ? y + h : maxY;
  6901. }
  6902. else
  6903. {
  6904. // POLY
  6905. for (var j = 0; j < points.length; j+=2)
  6906. {
  6907. x = points[j];
  6908. y = points[j+1];
  6909. minX = x-lineWidth < minX ? x-lineWidth : minX;
  6910. maxX = x+lineWidth > maxX ? x+lineWidth : maxX;
  6911. minY = y-lineWidth < minY ? y-lineWidth : minY;
  6912. maxY = y+lineWidth > maxY ? y+lineWidth : maxY;
  6913. }
  6914. }
  6915. }
  6916. var padding = this.boundsPadding;
  6917. this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2);
  6918. };
  6919. /**
  6920. * Generates the cached sprite when the sprite has cacheAsBitmap = true
  6921. *
  6922. * @method _generateCachedSprite
  6923. * @private
  6924. */
  6925. PIXI.Graphics.prototype._generateCachedSprite = function()
  6926. {
  6927. var bounds = this.getLocalBounds();
  6928. if(!this._cachedSprite)
  6929. {
  6930. var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height);
  6931. var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
  6932. this._cachedSprite = new PIXI.Sprite(texture);
  6933. this._cachedSprite.buffer = canvasBuffer;
  6934. this._cachedSprite.worldTransform = this.worldTransform;
  6935. }
  6936. else
  6937. {
  6938. this._cachedSprite.buffer.resize(bounds.width, bounds.height);
  6939. }
  6940. // leverage the anchor to account for the offset of the element
  6941. this._cachedSprite.anchor.x = -( bounds.x / bounds.width );
  6942. this._cachedSprite.anchor.y = -( bounds.y / bounds.height );
  6943. // this._cachedSprite.buffer.context.save();
  6944. this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y);
  6945. PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context);
  6946. this._cachedSprite.alpha = this.alpha;
  6947. // this._cachedSprite.buffer.context.restore();
  6948. };
  6949. PIXI.Graphics.prototype.destroyCachedSprite = function()
  6950. {
  6951. this._cachedSprite.texture.destroy(true);
  6952. // let the gc collect the unused sprite
  6953. // TODO could be object pooled!
  6954. this._cachedSprite = null;
  6955. };
  6956. // SOME TYPES:
  6957. PIXI.Graphics.POLY = 0;
  6958. PIXI.Graphics.RECT = 1;
  6959. PIXI.Graphics.CIRC = 2;
  6960. PIXI.Graphics.ELIP = 3;
  6961. /**
  6962. * @author Mat Groves http://matgroves.com/
  6963. */
  6964. /**
  6965. * A tiling sprite is a fast way of rendering a tiling image
  6966. *
  6967. * @class TilingSprite
  6968. * @extends Sprite
  6969. * @constructor
  6970. * @param texture {Texture} the texture of the tiling sprite
  6971. * @param width {Number} the width of the tiling sprite
  6972. * @param height {Number} the height of the tiling sprite
  6973. */
  6974. PIXI.TilingSprite = function(texture, width, height)
  6975. {
  6976. PIXI.Sprite.call( this, texture);
  6977. /**
  6978. * The with of the tiling sprite
  6979. *
  6980. * @property width
  6981. * @type Number
  6982. */
  6983. this.width = width || 100;
  6984. /**
  6985. * The height of the tiling sprite
  6986. *
  6987. * @property height
  6988. * @type Number
  6989. */
  6990. this.height = height || 100;
  6991. /**
  6992. * The scaling of the image that is being tiled
  6993. *
  6994. * @property tileScale
  6995. * @type Point
  6996. */
  6997. this.tileScale = new PIXI.Point(1,1);
  6998. /**
  6999. * A point that represents the scale of the texture object
  7000. *
  7001. * @property tileScaleOffset
  7002. * @type Point
  7003. */
  7004. this.tileScaleOffset = new PIXI.Point(1,1);
  7005. /**
  7006. * The offset position of the image that is being tiled
  7007. *
  7008. * @property tilePosition
  7009. * @type Point
  7010. */
  7011. this.tilePosition = new PIXI.Point(0,0);
  7012. /**
  7013. * Whether this sprite is renderable or not
  7014. *
  7015. * @property renderable
  7016. * @type Boolean
  7017. * @default true
  7018. */
  7019. this.renderable = true;
  7020. /**
  7021. * The tint applied to the sprite. This is a hex value
  7022. *
  7023. * @property tint
  7024. * @type Number
  7025. * @default 0xFFFFFF
  7026. */
  7027. this.tint = 0xFFFFFF;
  7028. /**
  7029. * The blend mode to be applied to the sprite
  7030. *
  7031. * @property blendMode
  7032. * @type Number
  7033. * @default PIXI.blendModes.NORMAL;
  7034. */
  7035. this.blendMode = PIXI.blendModes.NORMAL;
  7036. };
  7037. // constructor
  7038. PIXI.TilingSprite.prototype = Object.create(PIXI.Sprite.prototype);
  7039. PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite;
  7040. /**
  7041. * The width of the sprite, setting this will actually modify the scale to achieve the value set
  7042. *
  7043. * @property width
  7044. * @type Number
  7045. */
  7046. Object.defineProperty(PIXI.TilingSprite.prototype, 'width', {
  7047. get: function() {
  7048. return this._width;
  7049. },
  7050. set: function(value) {
  7051. this._width = value;
  7052. }
  7053. });
  7054. /**
  7055. * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set
  7056. *
  7057. * @property height
  7058. * @type Number
  7059. */
  7060. Object.defineProperty(PIXI.TilingSprite.prototype, 'height', {
  7061. get: function() {
  7062. return this._height;
  7063. },
  7064. set: function(value) {
  7065. this._height = value;
  7066. }
  7067. });
  7068. /**
  7069. * When the texture is updated, this event will be fired to update the scale and frame
  7070. *
  7071. * @method onTextureUpdate
  7072. * @param event
  7073. * @private
  7074. */
  7075. PIXI.TilingSprite.prototype.onTextureUpdate = function()
  7076. {
  7077. this.updateFrame = true;
  7078. };
  7079. PIXI.TilingSprite.prototype.setTexture = function(texture)
  7080. {
  7081. if(this.texture === texture)return;
  7082. this.texture = texture;
  7083. this.refreshTexture = true;
  7084. /*
  7085. if(this.tilingTexture)
  7086. {
  7087. this.generateTilingTexture(true);
  7088. }
  7089. */
  7090. /*
  7091. // stop current texture;
  7092. if(this.texture.baseTexture !== texture.baseTexture)
  7093. {
  7094. this.textureChange = true;
  7095. this.texture = texture;
  7096. }
  7097. else
  7098. {
  7099. this.texture = texture;
  7100. }
  7101. this.updateFrame = true;*/
  7102. this.cachedTint = 0xFFFFFF;
  7103. };
  7104. /**
  7105. * Renders the object using the WebGL renderer
  7106. *
  7107. * @method _renderWebGL
  7108. * @param renderSession {RenderSession}
  7109. * @private
  7110. */
  7111. PIXI.TilingSprite.prototype._renderWebGL = function(renderSession)
  7112. {
  7113. if(this.visible === false || this.alpha === 0)return;
  7114. var i,j;
  7115. if(this.mask)
  7116. {
  7117. renderSession.spriteBatch.stop();
  7118. renderSession.maskManager.pushMask(this.mask, renderSession);
  7119. renderSession.spriteBatch.start();
  7120. }
  7121. if(this.filters)
  7122. {
  7123. renderSession.spriteBatch.flush();
  7124. renderSession.filterManager.pushFilter(this._filterBlock);
  7125. }
  7126. if(!this.tilingTexture || this.refreshTexture)
  7127. {
  7128. this.generateTilingTexture(true);
  7129. if(this.tilingTexture && this.tilingTexture.needsUpdate)
  7130. {
  7131. //TODO - tweaking
  7132. PIXI.updateWebGLTexture(this.tilingTexture.baseTexture, renderSession.gl);
  7133. this.tilingTexture.needsUpdate = false;
  7134. // this.tilingTexture._uvs = null;
  7135. }
  7136. }
  7137. else renderSession.spriteBatch.renderTilingSprite(this);
  7138. // simple render children!
  7139. for(i=0,j=this.children.length; i<j; i++)
  7140. {
  7141. this.children[i]._renderWebGL(renderSession);
  7142. }
  7143. renderSession.spriteBatch.stop();
  7144. if(this.filters)renderSession.filterManager.popFilter();
  7145. if(this.mask)renderSession.maskManager.popMask(renderSession);
  7146. renderSession.spriteBatch.start();
  7147. };
  7148. /**
  7149. * Renders the object using the Canvas renderer
  7150. *
  7151. * @method _renderCanvas
  7152. * @param renderSession {RenderSession}
  7153. * @private
  7154. */
  7155. PIXI.TilingSprite.prototype._renderCanvas = function(renderSession)
  7156. {
  7157. if(this.visible === false || this.alpha === 0)return;
  7158. var context = renderSession.context;
  7159. if(this._mask)
  7160. {
  7161. renderSession.maskManager.pushMask(this._mask, context);
  7162. }
  7163. context.globalAlpha = this.worldAlpha;
  7164. var transform = this.worldTransform;
  7165. // allow for trimming
  7166. //(this.anchor.x) * -frame.width,
  7167. // (this.anchor.y) * -frame.height,
  7168. context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx , transform.ty);
  7169. if(!this.__tilePattern || this.refreshTexture)
  7170. {
  7171. this.generateTilingTexture(false);
  7172. if(this.tilingTexture)
  7173. {
  7174. this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');
  7175. }
  7176. else
  7177. {
  7178. return;
  7179. }
  7180. }
  7181. // check blend mode
  7182. if(this.blendMode !== renderSession.currentBlendMode)
  7183. {
  7184. renderSession.currentBlendMode = this.blendMode;
  7185. context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  7186. }
  7187. context.beginPath();
  7188. var tilePosition = this.tilePosition;
  7189. var tileScale = this.tileScale;
  7190. tilePosition.x %= this.tilingTexture.baseTexture.width;
  7191. tilePosition.y %= this.tilingTexture.baseTexture.height;
  7192. // offset
  7193. context.scale(tileScale.x,tileScale.y);
  7194. context.translate(tilePosition.x, tilePosition.y);
  7195. context.fillStyle = this.__tilePattern;
  7196. // make sure to account for the anchor point..
  7197. context.fillRect(-tilePosition.x + (this.anchor.x * -this._width),-tilePosition.y + (this.anchor.y * -this._height),
  7198. this._width / tileScale.x, this._height / tileScale.y);
  7199. context.scale(1/tileScale.x, 1/tileScale.y);
  7200. context.translate(-tilePosition.x, -tilePosition.y);
  7201. context.closePath();
  7202. if(this._mask)
  7203. {
  7204. renderSession.maskManager.popMask(renderSession.context);
  7205. }
  7206. };
  7207. /**
  7208. * Returns the framing rectangle of the sprite as a PIXI.Rectangle object
  7209. *
  7210. * @method getBounds
  7211. * @return {Rectangle} the framing rectangle
  7212. */
  7213. PIXI.TilingSprite.prototype.getBounds = function()
  7214. {
  7215. var width = this._width;
  7216. var height = this._height;
  7217. var w0 = width * (1-this.anchor.x);
  7218. var w1 = width * -this.anchor.x;
  7219. var h0 = height * (1-this.anchor.y);
  7220. var h1 = height * -this.anchor.y;
  7221. var worldTransform = this.worldTransform;
  7222. var a = worldTransform.a;
  7223. var b = worldTransform.c;
  7224. var c = worldTransform.b;
  7225. var d = worldTransform.d;
  7226. var tx = worldTransform.tx;
  7227. var ty = worldTransform.ty;
  7228. var x1 = a * w1 + c * h1 + tx;
  7229. var y1 = d * h1 + b * w1 + ty;
  7230. var x2 = a * w0 + c * h1 + tx;
  7231. var y2 = d * h1 + b * w0 + ty;
  7232. var x3 = a * w0 + c * h0 + tx;
  7233. var y3 = d * h0 + b * w0 + ty;
  7234. var x4 = a * w1 + c * h0 + tx;
  7235. var y4 = d * h0 + b * w1 + ty;
  7236. var maxX = -Infinity;
  7237. var maxY = -Infinity;
  7238. var minX = Infinity;
  7239. var minY = Infinity;
  7240. minX = x1 < minX ? x1 : minX;
  7241. minX = x2 < minX ? x2 : minX;
  7242. minX = x3 < minX ? x3 : minX;
  7243. minX = x4 < minX ? x4 : minX;
  7244. minY = y1 < minY ? y1 : minY;
  7245. minY = y2 < minY ? y2 : minY;
  7246. minY = y3 < minY ? y3 : minY;
  7247. minY = y4 < minY ? y4 : minY;
  7248. maxX = x1 > maxX ? x1 : maxX;
  7249. maxX = x2 > maxX ? x2 : maxX;
  7250. maxX = x3 > maxX ? x3 : maxX;
  7251. maxX = x4 > maxX ? x4 : maxX;
  7252. maxY = y1 > maxY ? y1 : maxY;
  7253. maxY = y2 > maxY ? y2 : maxY;
  7254. maxY = y3 > maxY ? y3 : maxY;
  7255. maxY = y4 > maxY ? y4 : maxY;
  7256. var bounds = this._bounds;
  7257. bounds.x = minX;
  7258. bounds.width = maxX - minX;
  7259. bounds.y = minY;
  7260. bounds.height = maxY - minY;
  7261. // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  7262. this._currentBounds = bounds;
  7263. return bounds;
  7264. };
  7265. /**
  7266. *
  7267. * @method generateTilingTexture
  7268. *
  7269. * @param forcePowerOfTwo {Boolean} Whether we want to force the texture to be a power of two
  7270. */
  7271. PIXI.TilingSprite.prototype.generateTilingTexture = function(forcePowerOfTwo)
  7272. {
  7273. var texture = this.texture;
  7274. if(!texture.baseTexture.hasLoaded)return;
  7275. var baseTexture = texture.baseTexture;
  7276. var frame = texture.frame;
  7277. var targetWidth, targetHeight;
  7278. // check that the frame is the same size as the base texture.
  7279. var isFrame = frame.width !== baseTexture.width || frame.height !== baseTexture.height;
  7280. var newTextureRequired = false;
  7281. if(!forcePowerOfTwo)
  7282. {
  7283. if(isFrame)
  7284. {
  7285. targetWidth = frame.width;
  7286. targetHeight = frame.height;
  7287. newTextureRequired = true;
  7288. }
  7289. }
  7290. else
  7291. {
  7292. targetWidth = PIXI.getNextPowerOfTwo(frame.width);
  7293. targetHeight = PIXI.getNextPowerOfTwo(frame.height);
  7294. if(frame.width !== targetWidth && frame.height !== targetHeight)newTextureRequired = true;
  7295. }
  7296. if(newTextureRequired)
  7297. {
  7298. var canvasBuffer;
  7299. if(this.tilingTexture && this.tilingTexture.isTiling)
  7300. {
  7301. canvasBuffer = this.tilingTexture.canvasBuffer;
  7302. canvasBuffer.resize(targetWidth, targetHeight);
  7303. this.tilingTexture.baseTexture.width = targetWidth;
  7304. this.tilingTexture.baseTexture.height = targetHeight;
  7305. this.tilingTexture.needsUpdate = true;
  7306. }
  7307. else
  7308. {
  7309. canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight);
  7310. this.tilingTexture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
  7311. this.tilingTexture.canvasBuffer = canvasBuffer;
  7312. this.tilingTexture.isTiling = true;
  7313. }
  7314. canvasBuffer.context.drawImage(texture.baseTexture.source,
  7315. frame.x,
  7316. frame.y,
  7317. frame.width,
  7318. frame.height,
  7319. 0,
  7320. 0,
  7321. targetWidth,
  7322. targetHeight);
  7323. this.tileScaleOffset.x = frame.width / targetWidth;
  7324. this.tileScaleOffset.y = frame.height / targetHeight;
  7325. }
  7326. else
  7327. {
  7328. //TODO - switching?
  7329. if(this.tilingTexture && this.tilingTexture.isTiling)
  7330. {
  7331. // destroy the tiling texture!
  7332. // TODO could store this somewhere?
  7333. this.tilingTexture.destroy(true);
  7334. }
  7335. this.tileScaleOffset.x = 1;
  7336. this.tileScaleOffset.y = 1;
  7337. this.tilingTexture = texture;
  7338. }
  7339. this.refreshTexture = false;
  7340. this.tilingTexture.baseTexture._powerOf2 = true;
  7341. };
  7342. /**
  7343. * @author Mat Groves http://matgroves.com/ @Doormat23
  7344. */
  7345. PIXI.BaseTextureCache = {};
  7346. PIXI.texturesToUpdate = [];
  7347. PIXI.texturesToDestroy = [];
  7348. PIXI.BaseTextureCacheIdGenerator = 0;
  7349. /**
  7350. * A texture stores the information that represents an image. All textures have a base texture
  7351. *
  7352. * @class BaseTexture
  7353. * @uses EventTarget
  7354. * @constructor
  7355. * @param source {String} the source object (image or canvas)
  7356. * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts
  7357. */
  7358. PIXI.BaseTexture = function(source, scaleMode)
  7359. {
  7360. PIXI.EventTarget.call( this );
  7361. /**
  7362. * [read-only] The width of the base texture set when the image has loaded
  7363. *
  7364. * @property width
  7365. * @type Number
  7366. * @readOnly
  7367. */
  7368. this.width = 100;
  7369. /**
  7370. * [read-only] The height of the base texture set when the image has loaded
  7371. *
  7372. * @property height
  7373. * @type Number
  7374. * @readOnly
  7375. */
  7376. this.height = 100;
  7377. /**
  7378. * The scale mode to apply when scaling this texture
  7379. * @property scaleMode
  7380. * @type PIXI.scaleModes
  7381. * @default PIXI.scaleModes.LINEAR
  7382. */
  7383. this.scaleMode = scaleMode || PIXI.scaleModes.DEFAULT;
  7384. /**
  7385. * [read-only] Describes if the base texture has loaded or not
  7386. *
  7387. * @property hasLoaded
  7388. * @type Boolean
  7389. * @readOnly
  7390. */
  7391. this.hasLoaded = false;
  7392. /**
  7393. * The source that is loaded to create the texture
  7394. *
  7395. * @property source
  7396. * @type Image
  7397. */
  7398. this.source = source;
  7399. //TODO will be used for futer pixi 1.5...
  7400. this.id = PIXI.BaseTextureCacheIdGenerator++;
  7401. // used for webGL
  7402. this._glTextures = [];
  7403. if(!source)return;
  7404. if(this.source.complete || this.source.getContext)
  7405. {
  7406. this.hasLoaded = true;
  7407. this.width = this.source.width;
  7408. this.height = this.source.height;
  7409. PIXI.texturesToUpdate.push(this);
  7410. }
  7411. else
  7412. {
  7413. var scope = this;
  7414. this.source.onload = function() {
  7415. scope.hasLoaded = true;
  7416. scope.width = scope.source.width;
  7417. scope.height = scope.source.height;
  7418. // add it to somewhere...
  7419. PIXI.texturesToUpdate.push(scope);
  7420. scope.dispatchEvent( { type: 'loaded', content: scope } );
  7421. };
  7422. }
  7423. this.imageUrl = null;
  7424. this._powerOf2 = false;
  7425. };
  7426. PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture;
  7427. /**
  7428. * Destroys this base texture
  7429. *
  7430. * @method destroy
  7431. */
  7432. PIXI.BaseTexture.prototype.destroy = function()
  7433. {
  7434. if(this.imageUrl)
  7435. {
  7436. delete PIXI.BaseTextureCache[this.imageUrl];
  7437. this.imageUrl = null;
  7438. this.source.src = null;
  7439. }
  7440. this.source = null;
  7441. PIXI.texturesToDestroy.push(this);
  7442. };
  7443. /**
  7444. * Changes the source image of the texture
  7445. *
  7446. * @method updateSourceImage
  7447. * @param newSrc {String} the path of the image
  7448. */
  7449. PIXI.BaseTexture.prototype.updateSourceImage = function(newSrc)
  7450. {
  7451. this.hasLoaded = false;
  7452. this.source.src = null;
  7453. this.source.src = newSrc;
  7454. };
  7455. /**
  7456. * Helper function that returns a base texture based on an image url
  7457. * If the image is not in the base texture cache it will be created and loaded
  7458. *
  7459. * @static
  7460. * @method fromImage
  7461. * @param imageUrl {String} The image url of the texture
  7462. * @param crossorigin {Boolean}
  7463. * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts
  7464. * @return BaseTexture
  7465. */
  7466. PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin, scaleMode)
  7467. {
  7468. var baseTexture = PIXI.BaseTextureCache[imageUrl];
  7469. if(crossorigin === undefined)crossorigin = true;
  7470. if(!baseTexture)
  7471. {
  7472. // new Image() breaks tex loading in some versions of Chrome.
  7473. // See https://code.google.com/p/chromium/issues/detail?id=238071
  7474. var image = new Image();//document.createElement('img');
  7475. if (crossorigin)
  7476. {
  7477. image.crossOrigin = '';
  7478. }
  7479. image.src = imageUrl;
  7480. baseTexture = new PIXI.BaseTexture(image, scaleMode);
  7481. baseTexture.imageUrl = imageUrl;
  7482. PIXI.BaseTextureCache[imageUrl] = baseTexture;
  7483. }
  7484. return baseTexture;
  7485. };
  7486. PIXI.BaseTexture.fromCanvas = function(canvas, scaleMode)
  7487. {
  7488. if(!canvas._pixiId)
  7489. {
  7490. canvas._pixiId = 'canvas_' + PIXI.TextureCacheIdGenerator++;
  7491. }
  7492. var baseTexture = PIXI.BaseTextureCache[canvas._pixiId];
  7493. if(!baseTexture)
  7494. {
  7495. baseTexture = new PIXI.BaseTexture(canvas, scaleMode);
  7496. PIXI.BaseTextureCache[canvas._pixiId] = baseTexture;
  7497. }
  7498. return baseTexture;
  7499. };
  7500. /**
  7501. * @author Mat Groves http://matgroves.com/ @Doormat23
  7502. */
  7503. PIXI.TextureCache = {};
  7504. PIXI.FrameCache = {};
  7505. PIXI.TextureCacheIdGenerator = 0;
  7506. /**
  7507. * A texture stores the information that represents an image or part of an image. It cannot be added
  7508. * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used
  7509. *
  7510. * @class Texture
  7511. * @uses EventTarget
  7512. * @constructor
  7513. * @param baseTexture {BaseTexture} The base texture source to create the texture from
  7514. * @param frame {Rectangle} The rectangle frame of the texture to show
  7515. */
  7516. PIXI.Texture = function(baseTexture, frame)
  7517. {
  7518. PIXI.EventTarget.call( this );
  7519. if(!frame)
  7520. {
  7521. this.noFrame = true;
  7522. frame = new PIXI.Rectangle(0,0,1,1);
  7523. }
  7524. if(baseTexture instanceof PIXI.Texture)
  7525. baseTexture = baseTexture.baseTexture;
  7526. /**
  7527. * The base texture of that this texture uses
  7528. *
  7529. * @property baseTexture
  7530. * @type BaseTexture
  7531. */
  7532. this.baseTexture = baseTexture;
  7533. /**
  7534. * The frame specifies the region of the base texture that this texture uses
  7535. *
  7536. * @property frame
  7537. * @type Rectangle
  7538. */
  7539. this.frame = frame;
  7540. /**
  7541. * The trim point
  7542. *
  7543. * @property trim
  7544. * @type Rectangle
  7545. */
  7546. this.trim = null;
  7547. this.scope = this;
  7548. this._uvs = null;
  7549. if(baseTexture.hasLoaded)
  7550. {
  7551. if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height);
  7552. this.setFrame(frame);
  7553. }
  7554. else
  7555. {
  7556. var scope = this;
  7557. baseTexture.addEventListener('loaded', function(){ scope.onBaseTextureLoaded(); });
  7558. }
  7559. };
  7560. PIXI.Texture.prototype.constructor = PIXI.Texture;
  7561. /**
  7562. * Called when the base texture is loaded
  7563. *
  7564. * @method onBaseTextureLoaded
  7565. * @param event
  7566. * @private
  7567. */
  7568. PIXI.Texture.prototype.onBaseTextureLoaded = function()
  7569. {
  7570. var baseTexture = this.baseTexture;
  7571. baseTexture.removeEventListener( 'loaded', this.onLoaded );
  7572. if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height);
  7573. this.setFrame(this.frame);
  7574. this.scope.dispatchEvent( { type: 'update', content: this } );
  7575. };
  7576. /**
  7577. * Destroys this texture
  7578. *
  7579. * @method destroy
  7580. * @param destroyBase {Boolean} Whether to destroy the base texture as well
  7581. */
  7582. PIXI.Texture.prototype.destroy = function(destroyBase)
  7583. {
  7584. if(destroyBase) this.baseTexture.destroy();
  7585. };
  7586. /**
  7587. * Specifies the rectangle region of the baseTexture
  7588. *
  7589. * @method setFrame
  7590. * @param frame {Rectangle} The frame of the texture to set it to
  7591. */
  7592. PIXI.Texture.prototype.setFrame = function(frame)
  7593. {
  7594. this.frame = frame;
  7595. this.width = frame.width;
  7596. this.height = frame.height;
  7597. if(frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height)
  7598. {
  7599. throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this);
  7600. }
  7601. this.updateFrame = true;
  7602. PIXI.Texture.frameUpdates.push(this);
  7603. //this.dispatchEvent( { type: 'update', content: this } );
  7604. };
  7605. PIXI.Texture.prototype._updateWebGLuvs = function()
  7606. {
  7607. if(!this._uvs)this._uvs = new PIXI.TextureUvs();
  7608. var frame = this.frame;
  7609. var tw = this.baseTexture.width;
  7610. var th = this.baseTexture.height;
  7611. this._uvs.x0 = frame.x / tw;
  7612. this._uvs.y0 = frame.y / th;
  7613. this._uvs.x1 = (frame.x + frame.width) / tw;
  7614. this._uvs.y1 = frame.y / th;
  7615. this._uvs.x2 = (frame.x + frame.width) / tw;
  7616. this._uvs.y2 = (frame.y + frame.height) / th;
  7617. this._uvs.x3 = frame.x / tw;
  7618. this._uvs.y3 = (frame.y + frame.height) / th;
  7619. };
  7620. /**
  7621. * Helper function that returns a texture based on an image url
  7622. * If the image is not in the texture cache it will be created and loaded
  7623. *
  7624. * @static
  7625. * @method fromImage
  7626. * @param imageUrl {String} The image url of the texture
  7627. * @param crossorigin {Boolean} Whether requests should be treated as crossorigin
  7628. * @return Texture
  7629. */
  7630. PIXI.Texture.fromImage = function(imageUrl, crossorigin, scaleMode)
  7631. {
  7632. var texture = PIXI.TextureCache[imageUrl];
  7633. if(!texture)
  7634. {
  7635. texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin, scaleMode));
  7636. PIXI.TextureCache[imageUrl] = texture;
  7637. }
  7638. return texture;
  7639. };
  7640. /**
  7641. * Helper function that returns a texture based on a frame id
  7642. * If the frame id is not in the texture cache an error will be thrown
  7643. *
  7644. * @static
  7645. * @method fromFrame
  7646. * @param frameId {String} The frame id of the texture
  7647. * @return Texture
  7648. */
  7649. PIXI.Texture.fromFrame = function(frameId)
  7650. {
  7651. var texture = PIXI.TextureCache[frameId];
  7652. if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache ');
  7653. return texture;
  7654. };
  7655. /**
  7656. * Helper function that returns a texture based on a canvas element
  7657. * If the canvas is not in the texture cache it will be created and loaded
  7658. *
  7659. * @static
  7660. * @method fromCanvas
  7661. * @param canvas {Canvas} The canvas element source of the texture
  7662. * @return Texture
  7663. */
  7664. PIXI.Texture.fromCanvas = function(canvas, scaleMode)
  7665. {
  7666. var baseTexture = PIXI.BaseTexture.fromCanvas(canvas, scaleMode);
  7667. return new PIXI.Texture( baseTexture );
  7668. };
  7669. /**
  7670. * Adds a texture to the textureCache.
  7671. *
  7672. * @static
  7673. * @method addTextureToCache
  7674. * @param texture {Texture}
  7675. * @param id {String} the id that the texture will be stored against.
  7676. */
  7677. PIXI.Texture.addTextureToCache = function(texture, id)
  7678. {
  7679. PIXI.TextureCache[id] = texture;
  7680. };
  7681. /**
  7682. * Remove a texture from the textureCache.
  7683. *
  7684. * @static
  7685. * @method removeTextureFromCache
  7686. * @param id {String} the id of the texture to be removed
  7687. * @return {Texture} the texture that was removed
  7688. */
  7689. PIXI.Texture.removeTextureFromCache = function(id)
  7690. {
  7691. var texture = PIXI.TextureCache[id];
  7692. delete PIXI.TextureCache[id];
  7693. delete PIXI.BaseTextureCache[id];
  7694. return texture;
  7695. };
  7696. // this is more for webGL.. it contains updated frames..
  7697. PIXI.Texture.frameUpdates = [];
  7698. PIXI.TextureUvs = function()
  7699. {
  7700. this.x0 = 0;
  7701. this.y0 = 0;
  7702. this.x1 = 0;
  7703. this.y1 = 0;
  7704. this.x2 = 0;
  7705. this.y2 = 0;
  7706. this.x3 = 0;
  7707. this.y4 = 0;
  7708. };
  7709. /**
  7710. * @author Mat Groves http://matgroves.com/ @Doormat23
  7711. */
  7712. /**
  7713. A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it.
  7714. __Hint__: All DisplayObjects (exmpl. Sprites) that render on RenderTexture should be preloaded.
  7715. Otherwise black rectangles will be drawn instead.
  7716. 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:
  7717. var renderTexture = new PIXI.RenderTexture(800, 600);
  7718. var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
  7719. sprite.position.x = 800/2;
  7720. sprite.position.y = 600/2;
  7721. sprite.anchor.x = 0.5;
  7722. sprite.anchor.y = 0.5;
  7723. renderTexture.render(sprite);
  7724. Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used:
  7725. var doc = new PIXI.DisplayObjectContainer();
  7726. doc.addChild(sprite);
  7727. renderTexture.render(doc); // Renders to center of renderTexture
  7728. * @class RenderTexture
  7729. * @extends Texture
  7730. * @constructor
  7731. * @param width {Number} The width of the render texture
  7732. * @param height {Number} The height of the render texture
  7733. */
  7734. PIXI.RenderTexture = function(width, height, renderer)
  7735. {
  7736. PIXI.EventTarget.call( this );
  7737. /**
  7738. * The with of the render texture
  7739. *
  7740. * @property width
  7741. * @type Number
  7742. */
  7743. this.width = width || 100;
  7744. /**
  7745. * The height of the render texture
  7746. *
  7747. * @property height
  7748. * @type Number
  7749. */
  7750. this.height = height || 100;
  7751. /**
  7752. * The framing rectangle of the render texture
  7753. *
  7754. * @property frame
  7755. * @type Rectangle
  7756. */
  7757. this.frame = new PIXI.Rectangle(0, 0, this.width, this.height);
  7758. /**
  7759. * The base texture object that this texture uses
  7760. *
  7761. * @property baseTexture
  7762. * @type BaseTexture
  7763. */
  7764. this.baseTexture = new PIXI.BaseTexture();
  7765. this.baseTexture.width = this.width;
  7766. this.baseTexture.height = this.height;
  7767. this.baseTexture._glTextures = [];
  7768. this.baseTexture.hasLoaded = true;
  7769. // each render texture can only belong to one renderer at the moment if its webGL
  7770. this.renderer = renderer || PIXI.defaultRenderer;
  7771. if(this.renderer.type === PIXI.WEBGL_RENDERER)
  7772. {
  7773. var gl = this.renderer.gl;
  7774. this.textureBuffer = new PIXI.FilterTexture(gl, this.width, this.height);
  7775. this.baseTexture._glTextures[gl.id] = this.textureBuffer.texture;
  7776. this.render = this.renderWebGL;
  7777. this.projection = new PIXI.Point(this.width/2 , -this.height/2);
  7778. }
  7779. else
  7780. {
  7781. this.render = this.renderCanvas;
  7782. this.textureBuffer = new PIXI.CanvasBuffer(this.width, this.height);
  7783. this.baseTexture.source = this.textureBuffer.canvas;
  7784. }
  7785. PIXI.Texture.frameUpdates.push(this);
  7786. };
  7787. PIXI.RenderTexture.prototype = Object.create(PIXI.Texture.prototype);
  7788. PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture;
  7789. PIXI.RenderTexture.prototype.resize = function(width, height)
  7790. {
  7791. this.width = width;
  7792. this.height = height;
  7793. this.frame.width = this.width;
  7794. this.frame.height = this.height;
  7795. if(this.renderer.type === PIXI.WEBGL_RENDERER)
  7796. {
  7797. this.projection.x = this.width / 2;
  7798. this.projection.y = -this.height / 2;
  7799. var gl = this.renderer.gl;
  7800. gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTextures[gl.id]);
  7801. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  7802. }
  7803. else
  7804. {
  7805. this.textureBuffer.resize(this.width, this.height);
  7806. }
  7807. PIXI.Texture.frameUpdates.push(this);
  7808. };
  7809. /**
  7810. * This function will draw the display object to the texture.
  7811. *
  7812. * @method renderWebGL
  7813. * @param displayObject {DisplayObject} The display object to render this texture on
  7814. * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn
  7815. * @private
  7816. */
  7817. PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear)
  7818. {
  7819. //TOOD replace position with matrix..
  7820. var gl = this.renderer.gl;
  7821. gl.colorMask(true, true, true, true);
  7822. gl.viewport(0, 0, this.width, this.height);
  7823. gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer );
  7824. if(clear)this.textureBuffer.clear();
  7825. // THIS WILL MESS WITH HIT TESTING!
  7826. var children = displayObject.children;
  7827. //TODO -? create a new one??? dont think so!
  7828. var originalWorldTransform = displayObject.worldTransform;
  7829. displayObject.worldTransform = PIXI.RenderTexture.tempMatrix;
  7830. // modify to flip...
  7831. displayObject.worldTransform.d = -1;
  7832. displayObject.worldTransform.ty = this.projection.y * -2;
  7833. if(position)
  7834. {
  7835. displayObject.worldTransform.tx = position.x;
  7836. displayObject.worldTransform.ty -= position.y;
  7837. }
  7838. for(var i=0,j=children.length; i<j; i++)
  7839. {
  7840. children[i].updateTransform();
  7841. }
  7842. // update the textures!
  7843. PIXI.WebGLRenderer.updateTextures();
  7844. //
  7845. this.renderer.renderDisplayObject(displayObject, this.projection, this.textureBuffer.frameBuffer);
  7846. displayObject.worldTransform = originalWorldTransform;
  7847. };
  7848. /**
  7849. * This function will draw the display object to the texture.
  7850. *
  7851. * @method renderCanvas
  7852. * @param displayObject {DisplayObject} The display object to render this texture on
  7853. * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn
  7854. * @private
  7855. */
  7856. PIXI.RenderTexture.prototype.renderCanvas = function(displayObject, position, clear)
  7857. {
  7858. var children = displayObject.children;
  7859. var originalWorldTransform = displayObject.worldTransform;
  7860. displayObject.worldTransform = PIXI.RenderTexture.tempMatrix;
  7861. if(position)
  7862. {
  7863. displayObject.worldTransform.tx = position.x;
  7864. displayObject.worldTransform.ty = position.y;
  7865. }
  7866. for(var i = 0, j = children.length; i < j; i++)
  7867. {
  7868. children[i].updateTransform();
  7869. }
  7870. if(clear)this.textureBuffer.clear();
  7871. var context = this.textureBuffer.context;
  7872. this.renderer.renderDisplayObject(displayObject, context);
  7873. context.setTransform(1,0,0,1,0,0);
  7874. displayObject.worldTransform = originalWorldTransform;
  7875. };
  7876. PIXI.RenderTexture.tempMatrix = new PIXI.Matrix();
  7877. /**
  7878. * @author Mat Groves http://matgroves.com/ @Doormat23
  7879. */
  7880. if (typeof exports !== 'undefined') {
  7881. if (typeof module !== 'undefined' && module.exports) {
  7882. exports = module.exports = PIXI;
  7883. }
  7884. exports.PIXI = PIXI;
  7885. } else if (typeof define !== 'undefined' && define.amd) {
  7886. define('PIXI', (function() { return root.PIXI = PIXI; })() );
  7887. } else {
  7888. root.PIXI = PIXI;
  7889. }
  7890. }).call(this);
  7891. /**
  7892. * @author Richard Davey <rich@photonstorm.com>
  7893. * @copyright 2014 Photon Storm Ltd.
  7894. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  7895. *
  7896. * @overview
  7897. *
  7898. * Phaser - http://phaser.io
  7899. *
  7900. * v2.0.3 "Allorallen" - Built: Fri Apr 11 2014 13:08:30
  7901. *
  7902. * By Richard Davey http://www.photonstorm.com @photonstorm
  7903. *
  7904. * Phaser is a fun, free and fast 2D game framework for making HTML5 games
  7905. * for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
  7906. *
  7907. * Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
  7908. * Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
  7909. * Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
  7910. *
  7911. * Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser
  7912. * and my love of framework development originate.
  7913. *
  7914. * Follow development at http://phaser.io and on our forum
  7915. *
  7916. * "If you want your children to be intelligent, read them fairy tales."
  7917. * "If you want them to be more intelligent, read them more fairy tales."
  7918. * -- Albert Einstein
  7919. */
  7920. /**
  7921. * @author Richard Davey <rich@photonstorm.com>
  7922. * @copyright 2014 Photon Storm Ltd.
  7923. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  7924. */
  7925. (function(){
  7926. var root = this;
  7927. /* global Phaser:true */
  7928. /**
  7929. * @author Richard Davey <rich@photonstorm.com>
  7930. * @copyright 2014 Photon Storm Ltd.
  7931. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  7932. */
  7933. /**
  7934. * @namespace Phaser
  7935. */
  7936. var Phaser = Phaser || {
  7937. VERSION: '<%= version %>',
  7938. DEV_VERSION: '2.0.3',
  7939. GAMES: [],
  7940. AUTO: 0,
  7941. CANVAS: 1,
  7942. WEBGL: 2,
  7943. HEADLESS: 3,
  7944. NONE: 0,
  7945. LEFT: 1,
  7946. RIGHT: 2,
  7947. UP: 3,
  7948. DOWN: 4,
  7949. SPRITE: 0,
  7950. BUTTON: 1,
  7951. IMAGE: 2,
  7952. GRAPHICS: 3,
  7953. TEXT: 4,
  7954. TILESPRITE: 5,
  7955. BITMAPTEXT: 6,
  7956. GROUP: 7,
  7957. RENDERTEXTURE: 8,
  7958. TILEMAP: 9,
  7959. TILEMAPLAYER: 10,
  7960. EMITTER: 11,
  7961. POLYGON: 12,
  7962. BITMAPDATA: 13,
  7963. CANVAS_FILTER: 14,
  7964. WEBGL_FILTER: 15,
  7965. ELLIPSE: 16,
  7966. SPRITEBATCH: 17,
  7967. RETROFONT: 18,
  7968. // The various blend modes supported by pixi / phaser
  7969. blendModes: {
  7970. NORMAL:0,
  7971. ADD:1,
  7972. MULTIPLY:2,
  7973. SCREEN:3,
  7974. OVERLAY:4,
  7975. DARKEN:5,
  7976. LIGHTEN:6,
  7977. COLOR_DODGE:7,
  7978. COLOR_BURN:8,
  7979. HARD_LIGHT:9,
  7980. SOFT_LIGHT:10,
  7981. DIFFERENCE:11,
  7982. EXCLUSION:12,
  7983. HUE:13,
  7984. SATURATION:14,
  7985. COLOR:15,
  7986. LUMINOSITY:16
  7987. },
  7988. // The scale modes
  7989. scaleModes: {
  7990. DEFAULT:0,
  7991. LINEAR:0,
  7992. NEAREST:1
  7993. }
  7994. };
  7995. PIXI.InteractionManager = function () {
  7996. // We don't need this in Pixi, so we've removed it to save space
  7997. // however the Stage object expects a reference to it, so here is a dummy entry.
  7998. };
  7999. /* jshint supernew: true */
  8000. /**
  8001. * @author Richard Davey <rich@photonstorm.com>
  8002. * @copyright 2014 Photon Storm Ltd.
  8003. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  8004. */
  8005. /**
  8006. * @class Phaser.Utils
  8007. * @static
  8008. */
  8009. Phaser.Utils = {
  8010. /**
  8011. * Get a unit dimension from a string.
  8012. *
  8013. * @method Phaser.Utils.parseDimension
  8014. * @param {string|number} size - The size to parse.
  8015. * @param {number} dimension - The window dimension to check.
  8016. * @return {number} The parsed dimension.
  8017. */
  8018. parseDimension: function (size, dimension) {
  8019. var f = 0;
  8020. var px = 0;
  8021. if (typeof size === 'string')
  8022. {
  8023. // %?
  8024. if (size.substr(-1) === '%')
  8025. {
  8026. f = parseInt(size, 10) / 100;
  8027. if (dimension === 0)
  8028. {
  8029. px = window.innerWidth * f;
  8030. }
  8031. else
  8032. {
  8033. px = window.innerHeight * f;
  8034. }
  8035. }
  8036. else
  8037. {
  8038. px = parseInt(size, 10);
  8039. }
  8040. }
  8041. else
  8042. {
  8043. px = size;
  8044. }
  8045. return px;
  8046. },
  8047. /**
  8048. * A standard Fisher-Yates Array shuffle implementation.
  8049. * @method Phaser.Utils.shuffle
  8050. * @param {array} array - The array to shuffle.
  8051. * @return {array} The shuffled array.
  8052. */
  8053. shuffle: function (array) {
  8054. for (var i = array.length - 1; i > 0; i--)
  8055. {
  8056. var j = Math.floor(Math.random() * (i + 1));
  8057. var temp = array[i];
  8058. array[i] = array[j];
  8059. array[j] = temp;
  8060. }
  8061. return array;
  8062. },
  8063. /**
  8064. * Javascript string pad http://www.webtoolkit.info/.
  8065. * pad = the string to pad it out with (defaults to a space)
  8066. * dir = 1 (left), 2 (right), 3 (both)
  8067. * @method Phaser.Utils.pad
  8068. * @param {string} str - The target string.
  8069. * @param {number} len - The number of characters to be added.
  8070. * @param {number} pad - The string to pad it out with (defaults to a space).
  8071. * @param {number} [dir=3] The direction dir = 1 (left), 2 (right), 3 (both).
  8072. * @return {string} The padded string
  8073. */
  8074. pad: function (str, len, pad, dir) {
  8075. if (typeof(len) == "undefined") { var len = 0; }
  8076. if (typeof(pad) == "undefined") { var pad = ' '; }
  8077. if (typeof(dir) == "undefined") { var dir = 3; }
  8078. var padlen = 0;
  8079. if (len + 1 >= str.length)
  8080. {
  8081. switch (dir)
  8082. {
  8083. case 1:
  8084. str = new Array(len + 1 - str.length).join(pad) + str;
  8085. break;
  8086. case 3:
  8087. var right = Math.ceil((padlen = len - str.length) / 2);
  8088. var left = padlen - right;
  8089. str = new Array(left+1).join(pad) + str + new Array(right+1).join(pad);
  8090. break;
  8091. default:
  8092. str = str + new Array(len + 1 - str.length).join(pad);
  8093. break;
  8094. }
  8095. }
  8096. return str;
  8097. },
  8098. /**
  8099. * This is a slightly modified version of jQuery.isPlainObject. A plain object is an object whose internal class property is [object Object].
  8100. * @method Phaser.Utils.isPlainObject
  8101. * @param {object} obj - The object to inspect.
  8102. * @return {boolean} - true if the object is plain, otherwise false.
  8103. */
  8104. isPlainObject: function (obj) {
  8105. // Not plain objects:
  8106. // - Any object or value whose internal [[Class]] property is not "[object Object]"
  8107. // - DOM nodes
  8108. // - window
  8109. if (typeof(obj) !== "object" || obj.nodeType || obj === obj.window)
  8110. {
  8111. return false;
  8112. }
  8113. // Support: Firefox <20
  8114. // The try/catch suppresses exceptions thrown when attempting to access
  8115. // the "constructor" property of certain host objects, ie. |window.location|
  8116. // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
  8117. try {
  8118. if (obj.constructor && !({}).hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf"))
  8119. {
  8120. return false;
  8121. }
  8122. } catch (e) {
  8123. return false;
  8124. }
  8125. // If the function hasn't returned already, we're confident that
  8126. // |obj| is a plain object, created by {} or constructed with new Object
  8127. return true;
  8128. },
  8129. /**
  8130. * This is a slightly modified version of http://api.jquery.com/jQuery.extend/
  8131. * @method Phaser.Utils.extend
  8132. * @param {boolean} deep - Perform a deep copy?
  8133. * @param {object} target - The target object to copy to.
  8134. * @return {object} The extended object.
  8135. */
  8136. extend: function () {
  8137. var options, name, src, copy, copyIsArray, clone,
  8138. target = arguments[0] || {},
  8139. i = 1,
  8140. length = arguments.length,
  8141. deep = false;
  8142. // Handle a deep copy situation
  8143. if (typeof target === "boolean")
  8144. {
  8145. deep = target;
  8146. target = arguments[1] || {};
  8147. // skip the boolean and the target
  8148. i = 2;
  8149. }
  8150. // extend Phaser if only one argument is passed
  8151. if (length === i)
  8152. {
  8153. target = this;
  8154. --i;
  8155. }
  8156. for (; i < length; i++)
  8157. {
  8158. // Only deal with non-null/undefined values
  8159. if ((options = arguments[i]) != null)
  8160. {
  8161. // Extend the base object
  8162. for (name in options)
  8163. {
  8164. src = target[name];
  8165. copy = options[name];
  8166. // Prevent never-ending loop
  8167. if (target === copy)
  8168. {
  8169. continue;
  8170. }
  8171. // Recurse if we're merging plain objects or arrays
  8172. if (deep && copy && (Phaser.Utils.isPlainObject(copy) || (copyIsArray = Array.isArray(copy))))
  8173. {
  8174. if (copyIsArray)
  8175. {
  8176. copyIsArray = false;
  8177. clone = src && Array.isArray(src) ? src : [];
  8178. }
  8179. else
  8180. {
  8181. clone = src && Phaser.Utils.isPlainObject(src) ? src : {};
  8182. }
  8183. // Never move original objects, clone them
  8184. target[name] = Phaser.Utils.extend(deep, clone, copy);
  8185. // Don't bring in undefined values
  8186. }
  8187. else if (copy !== undefined)
  8188. {
  8189. target[name] = copy;
  8190. }
  8191. }
  8192. }
  8193. }
  8194. // Return the modified object
  8195. return target;
  8196. }
  8197. };
  8198. /**
  8199. * A polyfill for Function.prototype.bind
  8200. */
  8201. if (typeof Function.prototype.bind != 'function') {
  8202. /* jshint freeze: false */
  8203. Function.prototype.bind = (function () {
  8204. var slice = Array.prototype.slice;
  8205. return function (thisArg) {
  8206. var target = this, boundArgs = slice.call(arguments, 1);
  8207. if (typeof target != 'function')
  8208. {
  8209. throw new TypeError();
  8210. }
  8211. function bound() {
  8212. var args = boundArgs.concat(slice.call(arguments));
  8213. target.apply(this instanceof bound ? this : thisArg, args);
  8214. }
  8215. bound.prototype = (function F(proto) {
  8216. if (proto)
  8217. {
  8218. F.prototype = proto;
  8219. }
  8220. if (!(this instanceof F))
  8221. {
  8222. return new F;
  8223. }
  8224. })(target.prototype);
  8225. return bound;
  8226. };
  8227. })();
  8228. }
  8229. /**
  8230. * A polyfill for Array.isArray
  8231. */
  8232. if (!Array.isArray)
  8233. {
  8234. Array.isArray = function (arg)
  8235. {
  8236. return Object.prototype.toString.call(arg) == '[object Array]';
  8237. };
  8238. }
  8239. /**
  8240. * A polyfill for Array.forEach
  8241. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
  8242. */
  8243. if (!Array.prototype.forEach)
  8244. {
  8245. Array.prototype.forEach = function(fun /*, thisArg */)
  8246. {
  8247. "use strict";
  8248. if (this === void 0 || this === null)
  8249. {
  8250. throw new TypeError();
  8251. }
  8252. var t = Object(this);
  8253. var len = t.length >>> 0;
  8254. if (typeof fun !== "function")
  8255. {
  8256. throw new TypeError();
  8257. }
  8258. var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
  8259. for (var i = 0; i < len; i++)
  8260. {
  8261. if (i in t)
  8262. {
  8263. fun.call(thisArg, t[i], i, t);
  8264. }
  8265. }
  8266. };
  8267. }
  8268. /**
  8269. * @author Richard Davey <rich@photonstorm.com>
  8270. * @copyright 2014 Photon Storm Ltd.
  8271. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  8272. */
  8273. /**
  8274. * 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.
  8275. * @class Circle
  8276. * @classdesc Phaser - Circle
  8277. * @constructor
  8278. * @param {number} [x=0] - The x coordinate of the center of the circle.
  8279. * @param {number} [y=0] - The y coordinate of the center of the circle.
  8280. * @param {number} [diameter=0] - The diameter of the circle.
  8281. * @return {Phaser.Circle} This circle object
  8282. */
  8283. Phaser.Circle = function (x, y, diameter) {
  8284. x = x || 0;
  8285. y = y || 0;
  8286. diameter = diameter || 0;
  8287. /**
  8288. * @property {number} x - The x coordinate of the center of the circle.
  8289. */
  8290. this.x = x;
  8291. /**
  8292. * @property {number} y - The y coordinate of the center of the circle.
  8293. */
  8294. this.y = y;
  8295. /**
  8296. * @property {number} _diameter - The diameter of the circle.
  8297. * @private
  8298. */
  8299. this._diameter = diameter;
  8300. if (diameter > 0)
  8301. {
  8302. /**
  8303. * @property {number} _radius - The radius of the circle.
  8304. * @private
  8305. */
  8306. this._radius = diameter * 0.5;
  8307. }
  8308. else
  8309. {
  8310. this._radius = 0;
  8311. }
  8312. };
  8313. Phaser.Circle.prototype = {
  8314. /**
  8315. * The circumference of the circle.
  8316. * @method Phaser.Circle#circumference
  8317. * @return {number}
  8318. */
  8319. circumference: function () {
  8320. return 2 * (Math.PI * this._radius);
  8321. },
  8322. /**
  8323. * Sets the members of Circle to the specified values.
  8324. * @method Phaser.Circle#setTo
  8325. * @param {number} x - The x coordinate of the center of the circle.
  8326. * @param {number} y - The y coordinate of the center of the circle.
  8327. * @param {number} diameter - The diameter of the circle in pixels.
  8328. * @return {Circle} This circle object.
  8329. */
  8330. setTo: function (x, y, diameter) {
  8331. this.x = x;
  8332. this.y = y;
  8333. this._diameter = diameter;
  8334. this._radius = diameter * 0.5;
  8335. return this;
  8336. },
  8337. /**
  8338. * Copies the x, y and diameter properties from any given object to this Circle.
  8339. * @method Phaser.Circle#copyFrom
  8340. * @param {any} source - The object to copy from.
  8341. * @return {Circle} This Circle object.
  8342. */
  8343. copyFrom: function (source) {
  8344. return this.setTo(source.x, source.y, source.diameter);
  8345. },
  8346. /**
  8347. * Copies the x, y and diameter properties from this Circle to any given object.
  8348. * @method Phaser.Circle#copyTo
  8349. * @param {any} dest - The object to copy to.
  8350. * @return {Object} This dest object.
  8351. */
  8352. copyTo: function (dest) {
  8353. dest.x = this.x;
  8354. dest.y = this.y;
  8355. dest.diameter = this._diameter;
  8356. return dest;
  8357. },
  8358. /**
  8359. * Returns the distance from the center of the Circle object to the given object
  8360. * (can be Circle, Point or anything with x/y properties)
  8361. * @method Phaser.Circle#distance
  8362. * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
  8363. * @param {boolean} [round] - Round the distance to the nearest integer (default false).
  8364. * @return {number} The distance between this Point object and the destination Point object.
  8365. */
  8366. distance: function (dest, round) {
  8367. if (typeof round === "undefined") { round = false; }
  8368. if (round)
  8369. {
  8370. return Phaser.Math.distanceRound(this.x, this.y, dest.x, dest.y);
  8371. }
  8372. else
  8373. {
  8374. return Phaser.Math.distance(this.x, this.y, dest.x, dest.y);
  8375. }
  8376. },
  8377. /**
  8378. * Returns a new Circle object with the same values for the x, y, width, and height properties as this Circle object.
  8379. * @method Phaser.Circle#clone
  8380. * @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.
  8381. * @return {Phaser.Circle} The cloned Circle object.
  8382. */
  8383. clone: function (out) {
  8384. if (typeof out === "undefined")
  8385. {
  8386. out = new Phaser.Circle(this.x, this.y, this.diameter);
  8387. }
  8388. else
  8389. {
  8390. out.setTo(this.x, this.y, this.diameter);
  8391. }
  8392. return out;
  8393. },
  8394. /**
  8395. * Return true if the given x/y coordinates are within this Circle object.
  8396. * @method Phaser.Circle#contains
  8397. * @param {number} x - The X value of the coordinate to test.
  8398. * @param {number} y - The Y value of the coordinate to test.
  8399. * @return {boolean} True if the coordinates are within this circle, otherwise false.
  8400. */
  8401. contains: function (x, y) {
  8402. return Phaser.Circle.contains(this, x, y);
  8403. },
  8404. /**
  8405. * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
  8406. * @method Phaser.Circle#circumferencePoint
  8407. * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
  8408. * @param {boolean} asDegrees - Is the given angle in radians (false) or degrees (true)?
  8409. * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
  8410. * @return {Phaser.Point} The Point object holding the result.
  8411. */
  8412. circumferencePoint: function (angle, asDegrees, out) {
  8413. return Phaser.Circle.circumferencePoint(this, angle, asDegrees, out);
  8414. },
  8415. /**
  8416. * Adjusts the location of the Circle object, as determined by its center coordinate, by the specified amounts.
  8417. * @method Phaser.Circle#offset
  8418. * @param {number} dx - Moves the x value of the Circle object by this amount.
  8419. * @param {number} dy - Moves the y value of the Circle object by this amount.
  8420. * @return {Circle} This Circle object.
  8421. */
  8422. offset: function (dx, dy) {
  8423. this.x += dx;
  8424. this.y += dy;
  8425. return this;
  8426. },
  8427. /**
  8428. * 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.
  8429. * @method Phaser.Circle#offsetPoint
  8430. * @param {Point} point A Point object to use to offset this Circle object (or any valid object with exposed x and y properties).
  8431. * @return {Circle} This Circle object.
  8432. */
  8433. offsetPoint: function (point) {
  8434. return this.offset(point.x, point.y);
  8435. },
  8436. /**
  8437. * Returns a string representation of this object.
  8438. * @method Phaser.Circle#toString
  8439. * @return {string} a string representation of the instance.
  8440. */
  8441. toString: function () {
  8442. return "[{Phaser.Circle (x=" + this.x + " y=" + this.y + " diameter=" + this.diameter + " radius=" + this.radius + ")}]";
  8443. }
  8444. };
  8445. Phaser.Circle.prototype.constructor = Phaser.Circle;
  8446. /**
  8447. * The largest distance between any two points on the circle. The same as the radius * 2.
  8448. * @name Phaser.Circle#diameter
  8449. * @property {number} diameter - Gets or sets the diameter of the circle.
  8450. */
  8451. Object.defineProperty(Phaser.Circle.prototype, "diameter", {
  8452. get: function () {
  8453. return this._diameter;
  8454. },
  8455. set: function (value) {
  8456. if (value > 0)
  8457. {
  8458. this._diameter = value;
  8459. this._radius = value * 0.5;
  8460. }
  8461. }
  8462. });
  8463. /**
  8464. * 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.
  8465. * @name Phaser.Circle#radius
  8466. * @property {number} radius - Gets or sets the radius of the circle.
  8467. */
  8468. Object.defineProperty(Phaser.Circle.prototype, "radius", {
  8469. get: function () {
  8470. return this._radius;
  8471. },
  8472. set: function (value) {
  8473. if (value > 0)
  8474. {
  8475. this._radius = value;
  8476. this._diameter = value * 2;
  8477. }
  8478. }
  8479. });
  8480. /**
  8481. * 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.
  8482. * @name Phaser.Circle#left
  8483. * @propety {number} left - Gets or sets the value of the leftmost point of the circle.
  8484. */
  8485. Object.defineProperty(Phaser.Circle.prototype, "left", {
  8486. get: function () {
  8487. return this.x - this._radius;
  8488. },
  8489. set: function (value) {
  8490. if (value > this.x)
  8491. {
  8492. this._radius = 0;
  8493. this._diameter = 0;
  8494. }
  8495. else
  8496. {
  8497. this.radius = this.x - value;
  8498. }
  8499. }
  8500. });
  8501. /**
  8502. * 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.
  8503. * @name Phaser.Circle#right
  8504. * @property {number} right - Gets or sets the value of the rightmost point of the circle.
  8505. */
  8506. Object.defineProperty(Phaser.Circle.prototype, "right", {
  8507. get: function () {
  8508. return this.x + this._radius;
  8509. },
  8510. set: function (value) {
  8511. if (value < this.x)
  8512. {
  8513. this._radius = 0;
  8514. this._diameter = 0;
  8515. }
  8516. else
  8517. {
  8518. this.radius = value - this.x;
  8519. }
  8520. }
  8521. });
  8522. /**
  8523. * 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.
  8524. * @name Phaser.Circle#top
  8525. * @property {number} top - Gets or sets the top of the circle.
  8526. */
  8527. Object.defineProperty(Phaser.Circle.prototype, "top", {
  8528. get: function () {
  8529. return this.y - this._radius;
  8530. },
  8531. set: function (value) {
  8532. if (value > this.y)
  8533. {
  8534. this._radius = 0;
  8535. this._diameter = 0;
  8536. }
  8537. else
  8538. {
  8539. this.radius = this.y - value;
  8540. }
  8541. }
  8542. });
  8543. /**
  8544. * 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.
  8545. * @name Phaser.Circle#bottom
  8546. * @property {number} bottom - Gets or sets the bottom of the circle.
  8547. */
  8548. Object.defineProperty(Phaser.Circle.prototype, "bottom", {
  8549. get: function () {
  8550. return this.y + this._radius;
  8551. },
  8552. set: function (value) {
  8553. if (value < this.y)
  8554. {
  8555. this._radius = 0;
  8556. this._diameter = 0;
  8557. }
  8558. else
  8559. {
  8560. this.radius = value - this.y;
  8561. }
  8562. }
  8563. });
  8564. /**
  8565. * The area of this Circle.
  8566. * @name Phaser.Circle#area
  8567. * @property {number} area - The area of this circle.
  8568. * @readonly
  8569. */
  8570. Object.defineProperty(Phaser.Circle.prototype, "area", {
  8571. get: function () {
  8572. if (this._radius > 0)
  8573. {
  8574. return Math.PI * this._radius * this._radius;
  8575. }
  8576. else
  8577. {
  8578. return 0;
  8579. }
  8580. }
  8581. });
  8582. /**
  8583. * 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.
  8584. * 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.
  8585. * @name Phaser.Circle#empty
  8586. * @property {boolean} empty - Gets or sets the empty state of the circle.
  8587. */
  8588. Object.defineProperty(Phaser.Circle.prototype, "empty", {
  8589. get: function () {
  8590. return (this._diameter === 0);
  8591. },
  8592. set: function (value) {
  8593. if (value === true)
  8594. {
  8595. this.setTo(0, 0, 0);
  8596. }
  8597. }
  8598. });
  8599. /**
  8600. * Return true if the given x/y coordinates are within the Circle object.
  8601. * @method Phaser.Circle.contains
  8602. * @param {Phaser.Circle} a - The Circle to be checked.
  8603. * @param {number} x - The X value of the coordinate to test.
  8604. * @param {number} y - The Y value of the coordinate to test.
  8605. * @return {boolean} True if the coordinates are within this circle, otherwise false.
  8606. */
  8607. Phaser.Circle.contains = function (a, x, y) {
  8608. // Check if x/y are within the bounds first
  8609. if (a.radius > 0 && x >= a.left && x <= a.right && y >= a.top && y <= a.bottom)
  8610. {
  8611. var dx = (a.x - x) * (a.x - x);
  8612. var dy = (a.y - y) * (a.y - y);
  8613. return (dx + dy) <= (a.radius * a.radius);
  8614. }
  8615. else
  8616. {
  8617. return false;
  8618. }
  8619. };
  8620. /**
  8621. * Determines whether the two Circle objects match. This method compares the x, y and diameter properties.
  8622. * @method Phaser.Circle.equals
  8623. * @param {Phaser.Circle} a - The first Circle object.
  8624. * @param {Phaser.Circle} b - The second Circle object.
  8625. * @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.
  8626. */
  8627. Phaser.Circle.equals = function (a, b) {
  8628. return (a.x == b.x && a.y == b.y && a.diameter == b.diameter);
  8629. };
  8630. /**
  8631. * Determines whether the two Circle objects intersect.
  8632. * This method checks the radius distances between the two Circle objects to see if they intersect.
  8633. * @method Phaser.Circle.intersects
  8634. * @param {Phaser.Circle} a - The first Circle object.
  8635. * @param {Phaser.Circle} b - The second Circle object.
  8636. * @return {boolean} A value of true if the specified object intersects with this Circle object; otherwise false.
  8637. */
  8638. Phaser.Circle.intersects = function (a, b) {
  8639. return (Phaser.Math.distance(a.x, a.y, b.x, b.y) <= (a.radius + b.radius));
  8640. };
  8641. /**
  8642. * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
  8643. * @method Phaser.Circle.circumferencePoint
  8644. * @param {Phaser.Circle} a - The first Circle object.
  8645. * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
  8646. * @param {boolean} asDegrees - Is the given angle in radians (false) or degrees (true)?
  8647. * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
  8648. * @return {Phaser.Point} The Point object holding the result.
  8649. */
  8650. Phaser.Circle.circumferencePoint = function (a, angle, asDegrees, out) {
  8651. if (typeof asDegrees === "undefined") { asDegrees = false; }
  8652. if (typeof out === "undefined") { out = new Phaser.Point(); }
  8653. if (asDegrees === true)
  8654. {
  8655. angle = Phaser.Math.degToRad(angle);
  8656. }
  8657. out.x = a.x + a.radius * Math.cos(angle);
  8658. out.y = a.y + a.radius * Math.sin(angle);
  8659. return out;
  8660. };
  8661. /**
  8662. * Checks if the given Circle and Rectangle objects intersect.
  8663. * @method Phaser.Circle.intersectsRectangle
  8664. * @param {Phaser.Circle} c - The Circle object to test.
  8665. * @param {Phaser.Rectangle} r - The Rectangle object to test.
  8666. * @return {boolean} True if the two objects intersect, otherwise false.
  8667. */
  8668. Phaser.Circle.intersectsRectangle = function (c, r) {
  8669. var cx = Math.abs(c.x - r.x - r.halfWidth);
  8670. var xDist = r.halfWidth + c.radius;
  8671. if (cx > xDist)
  8672. {
  8673. return false;
  8674. }
  8675. var cy = Math.abs(c.y - r.y - r.halfHeight);
  8676. var yDist = r.halfHeight + c.radius;
  8677. if (cy > yDist)
  8678. {
  8679. return false;
  8680. }
  8681. if (cx <= r.halfWidth || cy <= r.halfHeight)
  8682. {
  8683. return true;
  8684. }
  8685. var xCornerDist = cx - r.halfWidth;
  8686. var yCornerDist = cy - r.halfHeight;
  8687. var xCornerDistSq = xCornerDist * xCornerDist;
  8688. var yCornerDistSq = yCornerDist * yCornerDist;
  8689. var maxCornerDistSq = c.radius * c.radius;
  8690. return xCornerDistSq + yCornerDistSq <= maxCornerDistSq;
  8691. };
  8692. // Because PIXI uses its own Circle, we'll replace it with ours to avoid duplicating code or confusion.
  8693. PIXI.Circle = Phaser.Circle;
  8694. /**
  8695. * @author Richard Davey <rich@photonstorm.com>
  8696. * @copyright 2014 Photon Storm Ltd.
  8697. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  8698. */
  8699. /**
  8700. * Creates a new Point. If you pass no parameters a Point is created set to (0,0).
  8701. * @class Phaser.Point
  8702. * @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.
  8703. * @constructor
  8704. * @param {number} x The horizontal position of this Point (default 0)
  8705. * @param {number} y The vertical position of this Point (default 0)
  8706. */
  8707. Phaser.Point = function (x, y) {
  8708. x = x || 0;
  8709. y = y || 0;
  8710. /**
  8711. * @property {number} x - The x coordinate of the point.
  8712. */
  8713. this.x = x;
  8714. /**
  8715. * @property {number} y - The y coordinate of the point.
  8716. */
  8717. this.y = y;
  8718. };
  8719. Phaser.Point.prototype = {
  8720. /**
  8721. * Copies the x and y properties from any given object to this Point.
  8722. * @method Phaser.Point#copyFrom
  8723. * @param {any} source - The object to copy from.
  8724. * @return {Point} This Point object.
  8725. */
  8726. copyFrom: function (source) {
  8727. return this.setTo(source.x, source.y);
  8728. },
  8729. /**
  8730. * Inverts the x and y values of this Point
  8731. * @method Phaser.Point#invert
  8732. * @return {Point} This Point object.
  8733. */
  8734. invert: function () {
  8735. return this.setTo(this.y, this.x);
  8736. },
  8737. /**
  8738. * Sets the x and y values of this Point object to the given coordinates.
  8739. * @method Phaser.Point#setTo
  8740. * @param {number} x - The horizontal position of this point.
  8741. * @param {number} y - The vertical position of this point.
  8742. * @return {Point} This Point object. Useful for chaining method calls.
  8743. */
  8744. setTo: function (x, y) {
  8745. this.x = x || 0;
  8746. this.y = y || ( (y !== 0) ? this.x : 0 );
  8747. return this;
  8748. },
  8749. /**
  8750. * Sets the x and y values of this Point object to the given coordinates.
  8751. * @method Phaser.Point#set
  8752. * @param {number} x - The horizontal position of this point.
  8753. * @param {number} y - The vertical position of this point.
  8754. * @return {Point} This Point object. Useful for chaining method calls.
  8755. */
  8756. set: function (x, y) {
  8757. this.x = x || 0;
  8758. this.y = y || ( (y !== 0) ? this.x : 0 );
  8759. return this;
  8760. },
  8761. /**
  8762. * Adds the given x and y values to this Point.
  8763. * @method Phaser.Point#add
  8764. * @param {number} x - The value to add to Point.x.
  8765. * @param {number} y - The value to add to Point.y.
  8766. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  8767. */
  8768. add: function (x, y) {
  8769. this.x += x;
  8770. this.y += y;
  8771. return this;
  8772. },
  8773. /**
  8774. * Subtracts the given x and y values from this Point.
  8775. * @method Phaser.Point#subtract
  8776. * @param {number} x - The value to subtract from Point.x.
  8777. * @param {number} y - The value to subtract from Point.y.
  8778. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  8779. */
  8780. subtract: function (x, y) {
  8781. this.x -= x;
  8782. this.y -= y;
  8783. return this;
  8784. },
  8785. /**
  8786. * Multiplies Point.x and Point.y by the given x and y values.
  8787. * @method Phaser.Point#multiply
  8788. * @param {number} x - The value to multiply Point.x by.
  8789. * @param {number} y - The value to multiply Point.x by.
  8790. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  8791. */
  8792. multiply: function (x, y) {
  8793. this.x *= x;
  8794. this.y *= y;
  8795. return this;
  8796. },
  8797. /**
  8798. * Divides Point.x and Point.y by the given x and y values.
  8799. * @method Phaser.Point#divide
  8800. * @param {number} x - The value to divide Point.x by.
  8801. * @param {number} y - The value to divide Point.x by.
  8802. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  8803. */
  8804. divide: function (x, y) {
  8805. this.x /= x;
  8806. this.y /= y;
  8807. return this;
  8808. },
  8809. /**
  8810. * Clamps the x value of this Point to be between the given min and max.
  8811. * @method Phaser.Point#clampX
  8812. * @param {number} min - The minimum value to clamp this Point to.
  8813. * @param {number} max - The maximum value to clamp this Point to.
  8814. * @return {Phaser.Point} This Point object.
  8815. */
  8816. clampX: function (min, max) {
  8817. this.x = Phaser.Math.clamp(this.x, min, max);
  8818. return this;
  8819. },
  8820. /**
  8821. * Clamps the y value of this Point to be between the given min and max
  8822. * @method Phaser.Point#clampY
  8823. * @param {number} min - The minimum value to clamp this Point to.
  8824. * @param {number} max - The maximum value to clamp this Point to.
  8825. * @return {Phaser.Point} This Point object.
  8826. */
  8827. clampY: function (min, max) {
  8828. this.y = Phaser.Math.clamp(this.y, min, max);
  8829. return this;
  8830. },
  8831. /**
  8832. * Clamps this Point object values to be between the given min and max.
  8833. * @method Phaser.Point#clamp
  8834. * @param {number} min - The minimum value to clamp this Point to.
  8835. * @param {number} max - The maximum value to clamp this Point to.
  8836. * @return {Phaser.Point} This Point object.
  8837. */
  8838. clamp: function (min, max) {
  8839. this.x = Phaser.Math.clamp(this.x, min, max);
  8840. this.y = Phaser.Math.clamp(this.y, min, max);
  8841. return this;
  8842. },
  8843. /**
  8844. * Creates a copy of the given Point.
  8845. * @method Phaser.Point#clone
  8846. * @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.
  8847. * @return {Phaser.Point} The new Point object.
  8848. */
  8849. clone: function (output) {
  8850. if (typeof output === "undefined")
  8851. {
  8852. output = new Phaser.Point(this.x, this.y);
  8853. }
  8854. else
  8855. {
  8856. output.setTo(this.x, this.y);
  8857. }
  8858. return output;
  8859. },
  8860. /**
  8861. * Copies the x and y properties from this Point to any given object.
  8862. * @method Phaser.Point#copyTo
  8863. * @param {any} dest - The object to copy to.
  8864. * @return {Object} The dest object.
  8865. */
  8866. copyTo: function(dest) {
  8867. dest.x = this.x;
  8868. dest.y = this.y;
  8869. return dest;
  8870. },
  8871. /**
  8872. * Returns the distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties)
  8873. * @method Phaser.Point#distance
  8874. * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
  8875. * @param {boolean} [round] - Round the distance to the nearest integer (default false).
  8876. * @return {number} The distance between this Point object and the destination Point object.
  8877. */
  8878. distance: function (dest, round) {
  8879. return Phaser.Point.distance(this, dest, round);
  8880. },
  8881. /**
  8882. * Determines whether the given objects x/y values are equal to this Point object.
  8883. * @method Phaser.Point#equals
  8884. * @param {Phaser.Point} a - The first object to compare.
  8885. * @return {boolean} A value of true if the Points are equal, otherwise false.
  8886. */
  8887. equals: function (a) {
  8888. return (a.x == this.x && a.y == this.y);
  8889. },
  8890. /**
  8891. * Rotates this Point around the x/y coordinates given to the desired angle.
  8892. * @method Phaser.Point#rotate
  8893. * @param {number} x - The x coordinate of the anchor point
  8894. * @param {number} y - The y coordinate of the anchor point
  8895. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point to.
  8896. * @param {boolean} asDegrees - Is the given rotation in radians (false) or degrees (true)?
  8897. * @param {number} [distance] - An optional distance constraint between the Point and the anchor.
  8898. * @return {Phaser.Point} The modified point object.
  8899. */
  8900. rotate: function (x, y, angle, asDegrees, distance) {
  8901. return Phaser.Point.rotate(this, x, y, angle, asDegrees, distance);
  8902. },
  8903. /**
  8904. * Calculates the length of the vector
  8905. * @method Phaser.Point#getMagnitude
  8906. * @return {number} the length of the vector
  8907. */
  8908. getMagnitude: function() {
  8909. return Math.sqrt((this.x * this.x) + (this.y * this.y));
  8910. },
  8911. /**
  8912. * Alters the length of the vector without changing the direction
  8913. * @method Phaser.Point#setMagnitude
  8914. * @param {number} magnitude the desired magnitude of the resulting vector
  8915. * @return {Phaser.Point} the modified original vector
  8916. */
  8917. setMagnitude: function(magnitude) {
  8918. return this.normalize().multiply(magnitude, magnitude);
  8919. },
  8920. /**
  8921. * Alters the vector so that its length is 1, but it retains the same direction
  8922. * @method Phaser.Point#normalize
  8923. * @return {Phaser.Point} the modified original vector
  8924. */
  8925. normalize: function() {
  8926. if(!this.isZero()) {
  8927. var m = this.getMagnitude();
  8928. this.x /= m;
  8929. this.y /= m;
  8930. }
  8931. return this;
  8932. },
  8933. /**
  8934. * Determine if this point is at 0,0
  8935. * @method Phaser.Point#isZero
  8936. * @return {boolean} True if this Point is 0,0, otherwise false
  8937. */
  8938. isZero: function() {
  8939. return (this.x === 0 && this.y === 0);
  8940. },
  8941. /**
  8942. * Returns a string representation of this object.
  8943. * @method Phaser.Point#toString
  8944. * @return {string} A string representation of the instance.
  8945. */
  8946. toString: function () {
  8947. return '[{Point (x=' + this.x + ' y=' + this.y + ')}]';
  8948. }
  8949. };
  8950. Phaser.Point.prototype.constructor = Phaser.Point;
  8951. /**
  8952. * Adds the coordinates of two points together to create a new point.
  8953. * @method Phaser.Point.add
  8954. * @param {Phaser.Point} a - The first Point object.
  8955. * @param {Phaser.Point} b - The second Point object.
  8956. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  8957. * @return {Phaser.Point} The new Point object.
  8958. */
  8959. Phaser.Point.add = function (a, b, out) {
  8960. if (typeof out === "undefined") { out = new Phaser.Point(); }
  8961. out.x = a.x + b.x;
  8962. out.y = a.y + b.y;
  8963. return out;
  8964. };
  8965. /**
  8966. * Subtracts the coordinates of two points to create a new point.
  8967. * @method Phaser.Point.subtract
  8968. * @param {Phaser.Point} a - The first Point object.
  8969. * @param {Phaser.Point} b - The second Point object.
  8970. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  8971. * @return {Phaser.Point} The new Point object.
  8972. */
  8973. Phaser.Point.subtract = function (a, b, out) {
  8974. if (typeof out === "undefined") { out = new Phaser.Point(); }
  8975. out.x = a.x - b.x;
  8976. out.y = a.y - b.y;
  8977. return out;
  8978. };
  8979. /**
  8980. * Multiplies the coordinates of two points to create a new point.
  8981. * @method Phaser.Point.multiply
  8982. * @param {Phaser.Point} a - The first Point object.
  8983. * @param {Phaser.Point} b - The second Point object.
  8984. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  8985. * @return {Phaser.Point} The new Point object.
  8986. */
  8987. Phaser.Point.multiply = function (a, b, out) {
  8988. if (typeof out === "undefined") { out = new Phaser.Point(); }
  8989. out.x = a.x * b.x;
  8990. out.y = a.y * b.y;
  8991. return out;
  8992. };
  8993. /**
  8994. * Divides the coordinates of two points to create a new point.
  8995. * @method Phaser.Point.divide
  8996. * @param {Phaser.Point} a - The first Point object.
  8997. * @param {Phaser.Point} b - The second Point object.
  8998. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  8999. * @return {Phaser.Point} The new Point object.
  9000. */
  9001. Phaser.Point.divide = function (a, b, out) {
  9002. if (typeof out === "undefined") { out = new Phaser.Point(); }
  9003. out.x = a.x / b.x;
  9004. out.y = a.y / b.y;
  9005. return out;
  9006. };
  9007. /**
  9008. * Determines whether the two given Point objects are equal. They are considered equal if they have the same x and y values.
  9009. * @method Phaser.Point.equals
  9010. * @param {Phaser.Point} a - The first Point object.
  9011. * @param {Phaser.Point} b - The second Point object.
  9012. * @return {boolean} A value of true if the Points are equal, otherwise false.
  9013. */
  9014. Phaser.Point.equals = function (a, b) {
  9015. return (a.x == b.x && a.y == b.y);
  9016. };
  9017. /**
  9018. * Returns the distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties).
  9019. * @method Phaser.Point.distance
  9020. * @param {object} a - The target object. Must have visible x and y properties that represent the center of the object.
  9021. * @param {object} b - The target object. Must have visible x and y properties that represent the center of the object.
  9022. * @param {boolean} [round] - Round the distance to the nearest integer (default false).
  9023. * @return {number} The distance between this Point object and the destination Point object.
  9024. */
  9025. Phaser.Point.distance = function (a, b, round) {
  9026. if (typeof round === "undefined") { round = false; }
  9027. if (round)
  9028. {
  9029. return Phaser.Math.distanceRound(a.x, a.y, b.x, b.y);
  9030. }
  9031. else
  9032. {
  9033. return Phaser.Math.distance(a.x, a.y, b.x, b.y);
  9034. }
  9035. };
  9036. /**
  9037. * Rotates a Point around the x/y coordinates given to the desired angle.
  9038. * @method Phaser.Point.rotate
  9039. * @param {Phaser.Point} a - The Point object to rotate.
  9040. * @param {number} x - The x coordinate of the anchor point
  9041. * @param {number} y - The y coordinate of the anchor point
  9042. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point to.
  9043. * @param {boolean} asDegrees - Is the given rotation in radians (false) or degrees (true)?
  9044. * @param {number} distance - An optional distance constraint between the Point and the anchor.
  9045. * @return {Phaser.Point} The modified point object.
  9046. */
  9047. Phaser.Point.rotate = function (a, x, y, angle, asDegrees, distance) {
  9048. asDegrees = asDegrees || false;
  9049. distance = distance || null;
  9050. if (asDegrees)
  9051. {
  9052. angle = Phaser.Math.degToRad(angle);
  9053. }
  9054. // Get distance from origin (cx/cy) to this point
  9055. if (distance === null)
  9056. {
  9057. distance = Math.sqrt(((x - a.x) * (x - a.x)) + ((y - a.y) * (y - a.y)));
  9058. }
  9059. return a.setTo(x + distance * Math.cos(angle), y + distance * Math.sin(angle));
  9060. };
  9061. /**
  9062. * Calculates centroid (or midpoint) from an array of points. If only one point is provided, that point is returned.
  9063. * @method Phaser.Point.centroid
  9064. * @param {Phaser.Point[]} points - The array of one or more points.
  9065. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  9066. * @return {Phaser.Point} The new Point object.
  9067. */
  9068. Phaser.Point.centroid = function (points, out) {
  9069. if (typeof out === "undefined") { out = new Phaser.Point(); }
  9070. if (Object.prototype.toString.call(points) !== '[object Array]')
  9071. {
  9072. throw new Error("Phaser.Point. Parameter 'points' must be an array");
  9073. }
  9074. var pointslength = points.length;
  9075. if (pointslength < 1)
  9076. {
  9077. throw new Error("Phaser.Point. Parameter 'points' array must not be empty");
  9078. }
  9079. if (pointslength === 1)
  9080. {
  9081. out.copyFrom(points[0]);
  9082. return out;
  9083. }
  9084. for (var i = 0; i < pointslength; i++)
  9085. {
  9086. Phaser.Point.add(out, points[i], out);
  9087. }
  9088. out.divide(pointslength, pointslength);
  9089. return out;
  9090. };
  9091. // Because PIXI uses its own Point, we'll replace it with ours to avoid duplicating code or confusion.
  9092. PIXI.Point = Phaser.Point;
  9093. /**
  9094. * @author Richard Davey <rich@photonstorm.com>
  9095. * @copyright 2014 Photon Storm Ltd.
  9096. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  9097. */
  9098. /**
  9099. * 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.
  9100. *
  9101. * @class Phaser.Rectangle
  9102. * @constructor
  9103. * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
  9104. * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
  9105. * @param {number} width - The width of the Rectangle.
  9106. * @param {number} height - The height of the Rectangle.
  9107. * @return {Phaser.Rectangle} This Rectangle object.
  9108. */
  9109. Phaser.Rectangle = function (x, y, width, height) {
  9110. x = x || 0;
  9111. y = y || 0;
  9112. width = width || 0;
  9113. height = height || 0;
  9114. /**
  9115. * @property {number} x - The x coordinate of the top-left corner of the Rectangle.
  9116. */
  9117. this.x = x;
  9118. /**
  9119. * @property {number} y - The y coordinate of the top-left corner of the Rectangle.
  9120. */
  9121. this.y = y;
  9122. /**
  9123. * @property {number} width - The width of the Rectangle.
  9124. */
  9125. this.width = width;
  9126. /**
  9127. * @property {number} height - The height of the Rectangle.
  9128. */
  9129. this.height = height;
  9130. };
  9131. Phaser.Rectangle.prototype = {
  9132. /**
  9133. * Adjusts the location of the Rectangle object, as determined by its top-left corner, by the specified amounts.
  9134. * @method Phaser.Rectangle#offset
  9135. * @param {number} dx - Moves the x value of the Rectangle object by this amount.
  9136. * @param {number} dy - Moves the y value of the Rectangle object by this amount.
  9137. * @return {Phaser.Rectangle} This Rectangle object.
  9138. */
  9139. offset: function (dx, dy) {
  9140. this.x += dx;
  9141. this.y += dy;
  9142. return this;
  9143. },
  9144. /**
  9145. * 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.
  9146. * @method Phaser.Rectangle#offsetPoint
  9147. * @param {Phaser.Point} point - A Point object to use to offset this Rectangle object.
  9148. * @return {Phaser.Rectangle} This Rectangle object.
  9149. */
  9150. offsetPoint: function (point) {
  9151. return this.offset(point.x, point.y);
  9152. },
  9153. /**
  9154. * Sets the members of Rectangle to the specified values.
  9155. * @method Phaser.Rectangle#setTo
  9156. * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
  9157. * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
  9158. * @param {number} width - The width of the Rectangle in pixels.
  9159. * @param {number} height - The height of the Rectangle in pixels.
  9160. * @return {Phaser.Rectangle} This Rectangle object
  9161. */
  9162. setTo: function (x, y, width, height) {
  9163. this.x = x;
  9164. this.y = y;
  9165. this.width = width;
  9166. this.height = height;
  9167. return this;
  9168. },
  9169. /**
  9170. * Runs Math.floor() on both the x and y values of this Rectangle.
  9171. * @method Phaser.Rectangle#floor
  9172. */
  9173. floor: function () {
  9174. this.x = Math.floor(this.x);
  9175. this.y = Math.floor(this.y);
  9176. },
  9177. /**
  9178. * Runs Math.floor() on the x, y, width and height values of this Rectangle.
  9179. * @method Phaser.Rectangle#floorAll
  9180. */
  9181. floorAll: function () {
  9182. this.x = Math.floor(this.x);
  9183. this.y = Math.floor(this.y);
  9184. this.width = Math.floor(this.width);
  9185. this.height = Math.floor(this.height);
  9186. },
  9187. /**
  9188. * Copies the x, y, width and height properties from any given object to this Rectangle.
  9189. * @method Phaser.Rectangle#copyFrom
  9190. * @param {any} source - The object to copy from.
  9191. * @return {Phaser.Rectangle} This Rectangle object.
  9192. */
  9193. copyFrom: function (source) {
  9194. return this.setTo(source.x, source.y, source.width, source.height);
  9195. },
  9196. /**
  9197. * Copies the x, y, width and height properties from this Rectangle to any given object.
  9198. * @method Phaser.Rectangle#copyTo
  9199. * @param {any} source - The object to copy to.
  9200. * @return {object} This object.
  9201. */
  9202. copyTo: function (dest) {
  9203. dest.x = this.x;
  9204. dest.y = this.y;
  9205. dest.width = this.width;
  9206. dest.height = this.height;
  9207. return dest;
  9208. },
  9209. /**
  9210. * 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.
  9211. * @method Phaser.Rectangle#inflate
  9212. * @param {number} dx - The amount to be added to the left side of the Rectangle.
  9213. * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
  9214. * @return {Phaser.Rectangle} This Rectangle object.
  9215. */
  9216. inflate: function (dx, dy) {
  9217. return Phaser.Rectangle.inflate(this, dx, dy);
  9218. },
  9219. /**
  9220. * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
  9221. * @method Phaser.Rectangle#size
  9222. * @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.
  9223. * @return {Phaser.Point} The size of the Rectangle object.
  9224. */
  9225. size: function (output) {
  9226. return Phaser.Rectangle.size(this, output);
  9227. },
  9228. /**
  9229. * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
  9230. * @method Phaser.Rectangle#clone
  9231. * @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.
  9232. * @return {Phaser.Rectangle}
  9233. */
  9234. clone: function (output) {
  9235. return Phaser.Rectangle.clone(this, output);
  9236. },
  9237. /**
  9238. * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
  9239. * @method Phaser.Rectangle#contains
  9240. * @param {number} x - The x coordinate of the point to test.
  9241. * @param {number} y - The y coordinate of the point to test.
  9242. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9243. */
  9244. contains: function (x, y) {
  9245. return Phaser.Rectangle.contains(this, x, y);
  9246. },
  9247. /**
  9248. * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
  9249. * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
  9250. * @method Phaser.Rectangle#containsRect
  9251. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9252. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9253. */
  9254. containsRect: function (b) {
  9255. return Phaser.Rectangle.containsRect(this, b);
  9256. },
  9257. /**
  9258. * Determines whether the two Rectangles are equal.
  9259. * This method compares the x, y, width and height properties of each Rectangle.
  9260. * @method Phaser.Rectangle#equals
  9261. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9262. * @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.
  9263. */
  9264. equals: function (b) {
  9265. return Phaser.Rectangle.equals(this, b);
  9266. },
  9267. /**
  9268. * 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.
  9269. * @method Phaser.Rectangle#intersection
  9270. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9271. * @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.
  9272. * @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.
  9273. */
  9274. intersection: function (b, out) {
  9275. return Phaser.Rectangle.intersection(this, b, out);
  9276. },
  9277. /**
  9278. * Determines whether the two Rectangles intersect with each other.
  9279. * This method checks the x, y, width, and height properties of the Rectangles.
  9280. * @method Phaser.Rectangle#intersects
  9281. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9282. * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0.
  9283. * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
  9284. */
  9285. intersects: function (b, tolerance) {
  9286. return Phaser.Rectangle.intersects(this, b, tolerance);
  9287. },
  9288. /**
  9289. * Determines whether the object specified intersects (overlaps) with the given values.
  9290. * @method Phaser.Rectangle#intersectsRaw
  9291. * @param {number} left - Description.
  9292. * @param {number} right - Description.
  9293. * @param {number} top - Description.
  9294. * @param {number} bottomt - Description.
  9295. * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
  9296. * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
  9297. */
  9298. intersectsRaw: function (left, right, top, bottom, tolerance) {
  9299. return Phaser.Rectangle.intersectsRaw(this, left, right, top, bottom, tolerance);
  9300. },
  9301. /**
  9302. * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
  9303. * @method Phaser.Rectangle#union
  9304. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9305. * @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.
  9306. * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
  9307. */
  9308. union: function (b, out) {
  9309. return Phaser.Rectangle.union(this, b, out);
  9310. },
  9311. /**
  9312. * Returns a string representation of this object.
  9313. * @method Phaser.Rectangle#toString
  9314. * @return {string} A string representation of the instance.
  9315. */
  9316. toString: function () {
  9317. return "[{Rectangle (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + " empty=" + this.empty + ")}]";
  9318. }
  9319. };
  9320. /**
  9321. * @name Phaser.Rectangle#halfWidth
  9322. * @property {number} halfWidth - Half of the width of the Rectangle.
  9323. * @readonly
  9324. */
  9325. Object.defineProperty(Phaser.Rectangle.prototype, "halfWidth", {
  9326. get: function () {
  9327. return Math.round(this.width / 2);
  9328. }
  9329. });
  9330. /**
  9331. * @name Phaser.Rectangle#halfHeight
  9332. * @property {number} halfHeight - Half of the height of the Rectangle.
  9333. * @readonly
  9334. */
  9335. Object.defineProperty(Phaser.Rectangle.prototype, "halfHeight", {
  9336. get: function () {
  9337. return Math.round(this.height / 2);
  9338. }
  9339. });
  9340. /**
  9341. * 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.
  9342. * @name Phaser.Rectangle#bottom
  9343. * @property {number} bottom - The sum of the y and height properties.
  9344. */
  9345. Object.defineProperty(Phaser.Rectangle.prototype, "bottom", {
  9346. get: function () {
  9347. return this.y + this.height;
  9348. },
  9349. set: function (value) {
  9350. if (value <= this.y) {
  9351. this.height = 0;
  9352. } else {
  9353. this.height = (this.y - value);
  9354. }
  9355. }
  9356. });
  9357. /**
  9358. * The location of the Rectangles bottom right corner as a Point object.
  9359. * @name Phaser.Rectangle#bottom
  9360. * @property {Phaser.Point} bottomRight - Gets or sets the location of the Rectangles bottom right corner as a Point object.
  9361. */
  9362. Object.defineProperty(Phaser.Rectangle.prototype, "bottomRight", {
  9363. get: function () {
  9364. return new Phaser.Point(this.right, this.bottom);
  9365. },
  9366. set: function (value) {
  9367. this.right = value.x;
  9368. this.bottom = value.y;
  9369. }
  9370. });
  9371. /**
  9372. * 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.
  9373. * @name Phaser.Rectangle#left
  9374. * @property {number} left - The x coordinate of the left of the Rectangle.
  9375. */
  9376. Object.defineProperty(Phaser.Rectangle.prototype, "left", {
  9377. get: function () {
  9378. return this.x;
  9379. },
  9380. set: function (value) {
  9381. if (value >= this.right) {
  9382. this.width = 0;
  9383. } else {
  9384. this.width = this.right - value;
  9385. }
  9386. this.x = value;
  9387. }
  9388. });
  9389. /**
  9390. * 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.
  9391. * @name Phaser.Rectangle#right
  9392. * @property {number} right - The sum of the x and width properties.
  9393. */
  9394. Object.defineProperty(Phaser.Rectangle.prototype, "right", {
  9395. get: function () {
  9396. return this.x + this.width;
  9397. },
  9398. set: function (value) {
  9399. if (value <= this.x) {
  9400. this.width = 0;
  9401. } else {
  9402. this.width = this.x + value;
  9403. }
  9404. }
  9405. });
  9406. /**
  9407. * The volume of the Rectangle derived from width * height.
  9408. * @name Phaser.Rectangle#volume
  9409. * @property {number} volume - The volume of the Rectangle derived from width * height.
  9410. * @readonly
  9411. */
  9412. Object.defineProperty(Phaser.Rectangle.prototype, "volume", {
  9413. get: function () {
  9414. return this.width * this.height;
  9415. }
  9416. });
  9417. /**
  9418. * The perimeter size of the Rectangle. This is the sum of all 4 sides.
  9419. * @name Phaser.Rectangle#perimeter
  9420. * @property {number} perimeter - The perimeter size of the Rectangle. This is the sum of all 4 sides.
  9421. * @readonly
  9422. */
  9423. Object.defineProperty(Phaser.Rectangle.prototype, "perimeter", {
  9424. get: function () {
  9425. return (this.width * 2) + (this.height * 2);
  9426. }
  9427. });
  9428. /**
  9429. * The x coordinate of the center of the Rectangle.
  9430. * @name Phaser.Rectangle#centerX
  9431. * @property {number} centerX - The x coordinate of the center of the Rectangle.
  9432. */
  9433. Object.defineProperty(Phaser.Rectangle.prototype, "centerX", {
  9434. get: function () {
  9435. return this.x + this.halfWidth;
  9436. },
  9437. set: function (value) {
  9438. this.x = value - this.halfWidth;
  9439. }
  9440. });
  9441. /**
  9442. * The y coordinate of the center of the Rectangle.
  9443. * @name Phaser.Rectangle#centerY
  9444. * @property {number} centerY - The y coordinate of the center of the Rectangle.
  9445. */
  9446. Object.defineProperty(Phaser.Rectangle.prototype, "centerY", {
  9447. get: function () {
  9448. return this.y + this.halfHeight;
  9449. },
  9450. set: function (value) {
  9451. this.y = value - this.halfHeight;
  9452. }
  9453. });
  9454. /**
  9455. * 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.
  9456. * However it does affect the height property, whereas changing the y value does not affect the height property.
  9457. * @name Phaser.Rectangle#top
  9458. * @property {number} top - The y coordinate of the top of the Rectangle.
  9459. */
  9460. Object.defineProperty(Phaser.Rectangle.prototype, "top", {
  9461. get: function () {
  9462. return this.y;
  9463. },
  9464. set: function (value) {
  9465. if (value >= this.bottom) {
  9466. this.height = 0;
  9467. this.y = value;
  9468. } else {
  9469. this.height = (this.bottom - value);
  9470. }
  9471. }
  9472. });
  9473. /**
  9474. * The location of the Rectangles top left corner as a Point object.
  9475. * @name Phaser.Rectangle#topLeft
  9476. * @property {Phaser.Point} topLeft - The location of the Rectangles top left corner as a Point object.
  9477. */
  9478. Object.defineProperty(Phaser.Rectangle.prototype, "topLeft", {
  9479. get: function () {
  9480. return new Phaser.Point(this.x, this.y);
  9481. },
  9482. set: function (value) {
  9483. this.x = value.x;
  9484. this.y = value.y;
  9485. }
  9486. });
  9487. /**
  9488. * 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.
  9489. * If set to true then all of the Rectangle properties are set to 0.
  9490. * @name Phaser.Rectangle#empty
  9491. * @property {boolean} empty - Gets or sets the Rectangles empty state.
  9492. */
  9493. Object.defineProperty(Phaser.Rectangle.prototype, "empty", {
  9494. get: function () {
  9495. return (!this.width || !this.height);
  9496. },
  9497. set: function (value) {
  9498. if (value === true)
  9499. {
  9500. this.setTo(0, 0, 0, 0);
  9501. }
  9502. }
  9503. });
  9504. Phaser.Rectangle.prototype.constructor = Phaser.Rectangle;
  9505. /**
  9506. * 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.
  9507. * @method Phaser.Rectangle.inflate
  9508. * @param {Phaser.Rectangle} a - The Rectangle object.
  9509. * @param {number} dx - The amount to be added to the left side of the Rectangle.
  9510. * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
  9511. * @return {Phaser.Rectangle} This Rectangle object.
  9512. */
  9513. Phaser.Rectangle.inflate = function (a, dx, dy) {
  9514. a.x -= dx;
  9515. a.width += 2 * dx;
  9516. a.y -= dy;
  9517. a.height += 2 * dy;
  9518. return a;
  9519. };
  9520. /**
  9521. * 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.
  9522. * @method Phaser.Rectangle.inflatePoint
  9523. * @param {Phaser.Rectangle} a - The Rectangle object.
  9524. * @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.
  9525. * @return {Phaser.Rectangle} The Rectangle object.
  9526. */
  9527. Phaser.Rectangle.inflatePoint = function (a, point) {
  9528. return Phaser.Rectangle.inflate(a, point.x, point.y);
  9529. };
  9530. /**
  9531. * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
  9532. * @method Phaser.Rectangle.size
  9533. * @param {Phaser.Rectangle} a - The Rectangle object.
  9534. * @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.
  9535. * @return {Phaser.Point} The size of the Rectangle object
  9536. */
  9537. Phaser.Rectangle.size = function (a, output) {
  9538. if (typeof output === "undefined")
  9539. {
  9540. output = new Phaser.Point(a.width, a.height);
  9541. }
  9542. else
  9543. {
  9544. output.setTo(a.width, a.height);
  9545. }
  9546. return output;
  9547. };
  9548. /**
  9549. * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
  9550. * @method Phaser.Rectangle.clone
  9551. * @param {Phaser.Rectangle} a - The Rectangle object.
  9552. * @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.
  9553. * @return {Phaser.Rectangle}
  9554. */
  9555. Phaser.Rectangle.clone = function (a, output) {
  9556. if (typeof output === "undefined")
  9557. {
  9558. output = new Phaser.Rectangle(a.x, a.y, a.width, a.height);
  9559. }
  9560. else
  9561. {
  9562. output.setTo(a.x, a.y, a.width, a.height);
  9563. }
  9564. return output;
  9565. };
  9566. /**
  9567. * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
  9568. * @method Phaser.Rectangle.contains
  9569. * @param {Phaser.Rectangle} a - The Rectangle object.
  9570. * @param {number} x - The x coordinate of the point to test.
  9571. * @param {number} y - The y coordinate of the point to test.
  9572. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9573. */
  9574. Phaser.Rectangle.contains = function (a, x, y) {
  9575. if (a.width <= 0 || a.height <= 0)
  9576. {
  9577. return false;
  9578. }
  9579. return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom);
  9580. };
  9581. /**
  9582. * Determines whether the specified coordinates are contained within the region defined by the given raw values.
  9583. * @method Phaser.Rectangle.containsRaw
  9584. * @param {number} rx - The x coordinate of the top left of the area.
  9585. * @param {number} ry - The y coordinate of the top left of the area.
  9586. * @param {number} rw - The width of the area.
  9587. * @param {number} rh - The height of the area.
  9588. * @param {number} x - The x coordinate of the point to test.
  9589. * @param {number} y - The y coordinate of the point to test.
  9590. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9591. */
  9592. Phaser.Rectangle.containsRaw = function (rx, ry, rw, rh, x, y) {
  9593. return (x >= rx && x <= (rx + rw) && y >= ry && y <= (ry + rh));
  9594. };
  9595. /**
  9596. * 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.
  9597. * @method Phaser.Rectangle.containsPoint
  9598. * @param {Phaser.Rectangle} a - The Rectangle object.
  9599. * @param {Phaser.Point} point - The point object being checked. Can be Point or any object with .x and .y values.
  9600. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9601. */
  9602. Phaser.Rectangle.containsPoint = function (a, point) {
  9603. return Phaser.Rectangle.contains(a, point.x, point.y);
  9604. };
  9605. /**
  9606. * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
  9607. * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
  9608. * @method Phaser.Rectangle.containsRect
  9609. * @param {Phaser.Rectangle} a - The first Rectangle object.
  9610. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9611. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  9612. */
  9613. Phaser.Rectangle.containsRect = function (a, b) {
  9614. // If the given rect has a larger volume than this one then it can never contain it
  9615. if (a.volume > b.volume)
  9616. {
  9617. return false;
  9618. }
  9619. return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom);
  9620. };
  9621. /**
  9622. * Determines whether the two Rectangles are equal.
  9623. * This method compares the x, y, width and height properties of each Rectangle.
  9624. * @method Phaser.Rectangle.equals
  9625. * @param {Phaser.Rectangle} a - The first Rectangle object.
  9626. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9627. * @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.
  9628. */
  9629. Phaser.Rectangle.equals = function (a, b) {
  9630. return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height);
  9631. };
  9632. /**
  9633. * 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.
  9634. * @method Phaser.Rectangle.intersection
  9635. * @param {Phaser.Rectangle} a - The first Rectangle object.
  9636. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9637. * @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.
  9638. * @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.
  9639. */
  9640. Phaser.Rectangle.intersection = function (a, b, output) {
  9641. if (typeof output === "undefined")
  9642. {
  9643. output = new Phaser.Rectangle();
  9644. }
  9645. if (Phaser.Rectangle.intersects(a, b))
  9646. {
  9647. output.x = Math.max(a.x, b.x);
  9648. output.y = Math.max(a.y, b.y);
  9649. output.width = Math.min(a.right, b.right) - output.x;
  9650. output.height = Math.min(a.bottom, b.bottom) - output.y;
  9651. }
  9652. return output;
  9653. };
  9654. /**
  9655. * Determines whether the two Rectangles intersect with each other.
  9656. * This method checks the x, y, width, and height properties of the Rectangles.
  9657. * @method Phaser.Rectangle.intersects
  9658. * @param {Phaser.Rectangle} a - The first Rectangle object.
  9659. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9660. * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
  9661. */
  9662. Phaser.Rectangle.intersects = function (a, b) {
  9663. if (a.width <= 0 || a.height <= 0 || b.width <= 0 || b.height <= 0)
  9664. {
  9665. return false;
  9666. }
  9667. return !(a.right < b.x || a.bottom < b.y || a.x > b.right || a.y > b.bottom);
  9668. };
  9669. /**
  9670. * Determines whether the object specified intersects (overlaps) with the given values.
  9671. * @method Phaser.Rectangle.intersectsRaw
  9672. * @param {number} left - Description.
  9673. * @param {number} right - Description.
  9674. * @param {number} top - Description.
  9675. * @param {number} bottom - Description.
  9676. * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
  9677. * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
  9678. */
  9679. Phaser.Rectangle.intersectsRaw = function (a, left, right, top, bottom, tolerance) {
  9680. if (typeof tolerance === "undefined") { tolerance = 0; }
  9681. return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance);
  9682. };
  9683. /**
  9684. * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
  9685. * @method Phaser.Rectangle.union
  9686. * @param {Phaser.Rectangle} a - The first Rectangle object.
  9687. * @param {Phaser.Rectangle} b - The second Rectangle object.
  9688. * @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.
  9689. * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
  9690. */
  9691. Phaser.Rectangle.union = function (a, b, output) {
  9692. if (typeof output === "undefined")
  9693. {
  9694. output = new Phaser.Rectangle();
  9695. }
  9696. 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));
  9697. };
  9698. // Because PIXI uses its own Rectangle, we'll replace it with ours to avoid duplicating code or confusion.
  9699. PIXI.Rectangle = Phaser.Rectangle;
  9700. PIXI.EmptyRectangle = new Phaser.Rectangle(0, 0, 0, 0);
  9701. /**
  9702. * @author Richard Davey <rich@photonstorm.com>
  9703. * @copyright 2014 Photon Storm Ltd.
  9704. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  9705. */
  9706. /**
  9707. * Creates a new Line object with a start and an end point.
  9708. * @class Line
  9709. * @classdesc Phaser - Line
  9710. * @constructor
  9711. * @param {number} [x1=0] - The x coordinate of the start of the line.
  9712. * @param {number} [y1=0] - The y coordinate of the start of the line.
  9713. * @param {number} [x2=0] - The x coordinate of the end of the line.
  9714. * @param {number} [y2=0] - The y coordinate of the end of the line.
  9715. * @return {Phaser.Line} This line object
  9716. */
  9717. Phaser.Line = function (x1, y1, x2, y2) {
  9718. x1 = x1 || 0;
  9719. y1 = y1 || 0;
  9720. x2 = x2 || 0;
  9721. y2 = y2 || 0;
  9722. /**
  9723. * @property {Phaser.Point} start - The start point of the line.
  9724. */
  9725. this.start = new Phaser.Point(x1, y1);
  9726. /**
  9727. * @property {Phaser.Point} end - The end point of the line.
  9728. */
  9729. this.end = new Phaser.Point(x2, y2);
  9730. };
  9731. Phaser.Line.prototype = {
  9732. /**
  9733. * Sets the components of the Line to the specified values.
  9734. * @method Phaser.Line#setTo
  9735. * @param {number} [x1=0] - The x coordinate of the start of the line.
  9736. * @param {number} [y1=0] - The y coordinate of the start of the line.
  9737. * @param {number} [x2=0] - The x coordinate of the end of the line.
  9738. * @param {number} [y2=0] - The y coordinate of the end of the line.
  9739. * @return {Phaser.Line} This line object
  9740. */
  9741. setTo: function (x1, y1, x2, y2) {
  9742. this.start.setTo(x1, y1);
  9743. this.end.setTo(x2, y2);
  9744. return this;
  9745. },
  9746. /**
  9747. * Sets the line to match the x/y coordinates of the two given sprites.
  9748. * Can optionally be calculated from their center coordinates.
  9749. * @method Phaser.Line#fromSprite
  9750. * @param {Phaser.Sprite} startSprite - The coordinates of this Sprite will be set to the Line.start point.
  9751. * @param {Phaser.Sprite} endSprite - The coordinates of this Sprite will be set to the Line.start point.
  9752. * @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.
  9753. * @return {Phaser.Line} This line object
  9754. */
  9755. fromSprite: function (startSprite, endSprite, useCenter) {
  9756. if (typeof useCenter === 'undefined') { useCenter = false; }
  9757. if (useCenter)
  9758. {
  9759. return this.setTo(startSprite.center.x, startSprite.center.y, endSprite.center.x, endSprite.center.y);
  9760. }
  9761. else
  9762. {
  9763. return this.setTo(startSprite.x, startSprite.y, endSprite.x, endSprite.y);
  9764. }
  9765. },
  9766. /**
  9767. * Checks for intersection between this line and another Line.
  9768. * If asSegment is true it will check for segment intersection. If asSegment is false it will check for line intersection.
  9769. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  9770. *
  9771. * @method Phaser.Line#intersects
  9772. * @param {Phaser.Line} line - The line to check against this one.
  9773. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  9774. * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
  9775. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  9776. */
  9777. intersects: function (line, asSegment, result) {
  9778. return Phaser.Line.intersectsPoints(this.start, this.end, line.start, line.end, asSegment, result);
  9779. },
  9780. /**
  9781. * Tests if the given coordinates fall on this line. See pointOnSegment to test against just the line segment.
  9782. * @method Phaser.Line#pointOnLine
  9783. * @param {number} x - The line to check against this one.
  9784. * @param {number} y - The line to check against this one.
  9785. * @return {boolean} True if the point is on the line, false if not.
  9786. */
  9787. pointOnLine: function (x, y) {
  9788. return ((x - this.start.x) * (this.end.y - this.end.y) === (this.end.x - this.start.x) * (y - this.end.y));
  9789. },
  9790. /**
  9791. * Tests if the given coordinates fall on this line and within the segment. See pointOnLine to test against just the line.
  9792. * @method Phaser.Line#pointOnSegment
  9793. * @param {number} x - The line to check against this one.
  9794. * @param {number} y - The line to check against this one.
  9795. * @return {boolean} True if the point is on the line and segment, false if not.
  9796. */
  9797. pointOnSegment: function (x, y) {
  9798. var xMin = Math.min(this.start.x, this.end.x);
  9799. var xMax = Math.max(this.start.x, this.end.x);
  9800. var yMin = Math.min(this.start.y, this.end.y);
  9801. var yMax = Math.max(this.start.y, this.end.y);
  9802. return (this.pointOnLine(x, y) && (x >= xMin && x <= xMax) && (y >= yMin && y <= yMax));
  9803. },
  9804. /**
  9805. * Using Bresenham's line algorithm this will return an array of all coordinates on this line.
  9806. * The start and end points are rounded before this runs as the algorithm works on integers.
  9807. *
  9808. * @method Phaser.Line#coordinatesOnLine
  9809. * @param {number} [stepRate=1] - How many steps will we return? 1 = every coordinate on the line, 2 = every other coordinate, etc.
  9810. * @param {array} [results] - The array to store the results in. If not provided a new one will be generated.
  9811. * @return {array} An array of coordinates.
  9812. */
  9813. coordinatesOnLine: function (stepRate, results) {
  9814. if (typeof stepRate === 'undefined') { stepRate = 1; }
  9815. if (typeof results === 'undefined') { results = []; }
  9816. var x1 = Math.round(this.start.x);
  9817. var y1 = Math.round(this.start.y);
  9818. var x2 = Math.round(this.end.x);
  9819. var y2 = Math.round(this.end.y);
  9820. var dx = Math.abs(x2 - x1);
  9821. var dy = Math.abs(y2 - y1);
  9822. var sx = (x1 < x2) ? 1 : -1;
  9823. var sy = (y1 < y2) ? 1 : -1;
  9824. var err = dx - dy;
  9825. results.push([x1, y1]);
  9826. var i = 1;
  9827. while (!((x1 == x2) && (y1 == y2)))
  9828. {
  9829. var e2 = err << 1;
  9830. if (e2 > -dy)
  9831. {
  9832. err -= dy;
  9833. x1 += sx;
  9834. }
  9835. if (e2 < dx)
  9836. {
  9837. err += dx;
  9838. y1 += sy;
  9839. }
  9840. if (i % stepRate === 0)
  9841. {
  9842. results.push([x1, y1]);
  9843. }
  9844. i++;
  9845. }
  9846. return results;
  9847. }
  9848. };
  9849. /**
  9850. * @name Phaser.Line#length
  9851. * @property {number} length - Gets the length of the line segment.
  9852. * @readonly
  9853. */
  9854. Object.defineProperty(Phaser.Line.prototype, "length", {
  9855. get: function () {
  9856. 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));
  9857. }
  9858. });
  9859. /**
  9860. * @name Phaser.Line#angle
  9861. * @property {number} angle - Gets the angle of the line.
  9862. * @readonly
  9863. */
  9864. Object.defineProperty(Phaser.Line.prototype, "angle", {
  9865. get: function () {
  9866. return Math.atan2(this.end.x - this.start.x, this.end.y - this.start.y);
  9867. }
  9868. });
  9869. /**
  9870. * @name Phaser.Line#slope
  9871. * @property {number} slope - Gets the slope of the line (y/x).
  9872. * @readonly
  9873. */
  9874. Object.defineProperty(Phaser.Line.prototype, "slope", {
  9875. get: function () {
  9876. return (this.end.y - this.start.y) / (this.end.x - this.start.x);
  9877. }
  9878. });
  9879. /**
  9880. * @name Phaser.Line#perpSlope
  9881. * @property {number} perpSlope - Gets the perpendicular slope of the line (x/y).
  9882. * @readonly
  9883. */
  9884. Object.defineProperty(Phaser.Line.prototype, "perpSlope", {
  9885. get: function () {
  9886. return -((this.end.x - this.start.x) / (this.end.y - this.start.y));
  9887. }
  9888. });
  9889. /**
  9890. * @name Phaser.Line#x
  9891. * @property {number} x - Gets the x coordinate of the top left of the bounds around this line.
  9892. * @readonly
  9893. */
  9894. Object.defineProperty(Phaser.Line.prototype, "x", {
  9895. get: function () {
  9896. return Math.min(this.start.x, this.end.x);
  9897. }
  9898. });
  9899. /**
  9900. * @name Phaser.Line#y
  9901. * @property {number} y - Gets the y coordinate of the top left of the bounds around this line.
  9902. * @readonly
  9903. */
  9904. Object.defineProperty(Phaser.Line.prototype, "y", {
  9905. get: function () {
  9906. return Math.min(this.start.y, this.end.y);
  9907. }
  9908. });
  9909. /**
  9910. * @name Phaser.Line#left
  9911. * @property {number} left - Gets the left-most point of this line.
  9912. * @readonly
  9913. */
  9914. Object.defineProperty(Phaser.Line.prototype, "left", {
  9915. get: function () {
  9916. return Math.min(this.start.x, this.end.x);
  9917. }
  9918. });
  9919. /**
  9920. * @name Phaser.Line#right
  9921. * @property {number} right - Gets the right-most point of this line.
  9922. * @readonly
  9923. */
  9924. Object.defineProperty(Phaser.Line.prototype, "right", {
  9925. get: function () {
  9926. return Math.max(this.start.x, this.end.x);
  9927. }
  9928. });
  9929. /**
  9930. * @name Phaser.Line#top
  9931. * @property {number} top - Gets the top-most point of this line.
  9932. * @readonly
  9933. */
  9934. Object.defineProperty(Phaser.Line.prototype, "top", {
  9935. get: function () {
  9936. return Math.min(this.start.y, this.end.y);
  9937. }
  9938. });
  9939. /**
  9940. * @name Phaser.Line#bottom
  9941. * @property {number} bottom - Gets the bottom-most point of this line.
  9942. * @readonly
  9943. */
  9944. Object.defineProperty(Phaser.Line.prototype, "bottom", {
  9945. get: function () {
  9946. return Math.max(this.start.y, this.end.y);
  9947. }
  9948. });
  9949. /**
  9950. * @name Phaser.Line#width
  9951. * @property {number} width - Gets the width of this bounds of this line.
  9952. * @readonly
  9953. */
  9954. Object.defineProperty(Phaser.Line.prototype, "width", {
  9955. get: function () {
  9956. return Math.abs(this.start.x - this.end.x);
  9957. }
  9958. });
  9959. /**
  9960. * @name Phaser.Line#height
  9961. * @property {number} height - Gets the height of this bounds of this line.
  9962. * @readonly
  9963. */
  9964. Object.defineProperty(Phaser.Line.prototype, "height", {
  9965. get: function () {
  9966. return Math.abs(this.start.y - this.end.y);
  9967. }
  9968. });
  9969. /**
  9970. * Checks for intersection between two lines as defined by the given start and end points.
  9971. * If asSegment is true it will check for line segment intersection. If asSegment is false it will check for line intersection.
  9972. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  9973. * Adapted from code by Keith Hair
  9974. *
  9975. * @method Phaser.Line.intersectsPoints
  9976. * @param {Phaser.Point} a - The start of the first Line to be checked.
  9977. * @param {Phaser.Point} b - The end of the first line to be checked.
  9978. * @param {Phaser.Point} e - The start of the second Line to be checked.
  9979. * @param {Phaser.Point} f - The end of the second line to be checked.
  9980. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  9981. * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
  9982. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  9983. */
  9984. Phaser.Line.intersectsPoints = function (a, b, e, f, asSegment, result) {
  9985. if (typeof asSegment === 'undefined') { asSegment = true; }
  9986. if (typeof result === 'undefined') { result = new Phaser.Point(); }
  9987. var a1 = b.y - a.y;
  9988. var a2 = f.y - e.y;
  9989. var b1 = a.x - b.x;
  9990. var b2 = e.x - f.x;
  9991. var c1 = (b.x * a.y) - (a.x * b.y);
  9992. var c2 = (f.x * e.y) - (e.x * f.y);
  9993. var denom = (a1 * b2) - (a2 * b1);
  9994. if (denom === 0)
  9995. {
  9996. return null;
  9997. }
  9998. result.x = ((b1 * c2) - (b2 * c1)) / denom;
  9999. result.y = ((a2 * c1) - (a1 * c2)) / denom;
  10000. if (asSegment)
  10001. {
  10002. if (Math.pow((result.x - b.x) + (result.y - b.y), 2) > Math.pow((a.x - b.x) + (a.y - b.y), 2))
  10003. {
  10004. return null;
  10005. }
  10006. if (Math.pow((result.x - a.x) + (result.y - a.y), 2) > Math.pow((a.x - b.x) + (a.y - b.y), 2))
  10007. {
  10008. return null;
  10009. }
  10010. if (Math.pow((result.x - f.x) + (result.y - f.y), 2) > Math.pow((e.x - f.x) + (e.y - f.y), 2))
  10011. {
  10012. return null;
  10013. }
  10014. if (Math.pow((result.x - e.x) + (result.y - e.y), 2) > Math.pow((e.x - f.x) + (e.y - f.y), 2))
  10015. {
  10016. return null;
  10017. }
  10018. }
  10019. return result;
  10020. };
  10021. /**
  10022. * Checks for intersection between two lines.
  10023. * If asSegment is true it will check for segment intersection.
  10024. * If asSegment is false it will check for line intersection.
  10025. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  10026. * Adapted from code by Keith Hair
  10027. *
  10028. * @method Phaser.Line.intersects
  10029. * @param {Phaser.Line} a - The first Line to be checked.
  10030. * @param {Phaser.Line} b - The second Line to be checked.
  10031. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  10032. * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
  10033. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  10034. */
  10035. Phaser.Line.intersects = function (a, b, asSegment, result) {
  10036. return Phaser.Line.intersectsPoints(a.start, a.end, b.start, b.end, asSegment, result);
  10037. };
  10038. /**
  10039. * @author Richard Davey <rich@photonstorm.com>
  10040. * @author Chad Engler <chad@pantherdev.com>
  10041. * @copyright 2014 Photon Storm Ltd.
  10042. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10043. */
  10044. /**
  10045. * Creates a Ellipse object. A curve on a plane surrounding two focal points.
  10046. * @class Ellipse
  10047. * @classdesc Phaser - Ellipse
  10048. * @constructor
  10049. * @param {number} [x=0] - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10050. * @param {number} [y=0] - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10051. * @param {number} [width=0] - The overall width of this ellipse.
  10052. * @param {number} [height=0] - The overall height of this ellipse.
  10053. * @return {Phaser.Ellipse} This Ellipse object
  10054. */
  10055. Phaser.Ellipse = function (x, y, width, height) {
  10056. this.type = Phaser.ELLIPSE;
  10057. x = x || 0;
  10058. y = y || 0;
  10059. width = width || 0;
  10060. height = height || 0;
  10061. /**
  10062. * @property {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10063. */
  10064. this.x = x;
  10065. /**
  10066. * @property {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10067. */
  10068. this.y = y;
  10069. /**
  10070. * @property {number} width - The overall width of this ellipse.
  10071. */
  10072. this.width = width;
  10073. /**
  10074. * @property {number} height - The overall height of this ellipse.
  10075. */
  10076. this.height = height;
  10077. };
  10078. Phaser.Ellipse.prototype = {
  10079. /**
  10080. * Sets the members of the Ellipse to the specified values.
  10081. * @method Phaser.Ellipse#setTo
  10082. * @param {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10083. * @param {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  10084. * @param {number} width - The overall width of this ellipse.
  10085. * @param {number} height - The overall height of this ellipse.
  10086. * @return {Phaser.Ellipse} This Ellipse object.
  10087. */
  10088. setTo: function (x, y, width, height) {
  10089. this.x = x;
  10090. this.y = y;
  10091. this.width = width;
  10092. this.height = height;
  10093. return this;
  10094. },
  10095. /**
  10096. * Copies the x, y, width and height properties from any given object to this Ellipse.
  10097. * @method Phaser.Ellipse#copyFrom
  10098. * @param {any} source - The object to copy from.
  10099. * @return {Phaser.Ellipse} This Ellipse object.
  10100. */
  10101. copyFrom: function (source) {
  10102. return this.setTo(source.x, source.y, source.width, source.height);
  10103. },
  10104. /**
  10105. * Copies the x, y and diameter properties from this Circle to any given object.
  10106. * @method Phaser.Ellipse#copyTo
  10107. * @param {any} dest - The object to copy to.
  10108. * @return {Object} This dest object.
  10109. */
  10110. copyTo: function(dest) {
  10111. dest.x = this.x;
  10112. dest.y = this.y;
  10113. dest.width = this.width;
  10114. dest.height = this.height;
  10115. return dest;
  10116. },
  10117. /**
  10118. * Returns a new Ellipse object with the same values for the x, y, width, and height properties as this Ellipse object.
  10119. * @method Phaser.Ellipse#clone
  10120. * @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.
  10121. * @return {Phaser.Ellipse} The cloned Ellipse object.
  10122. */
  10123. clone: function(out) {
  10124. if (typeof out === "undefined")
  10125. {
  10126. out = new Phaser.Ellipse(this.x, this.y, this.width, this.height);
  10127. }
  10128. else
  10129. {
  10130. out.setTo(this.x, this.y, this.width, this.height);
  10131. }
  10132. return out;
  10133. },
  10134. /**
  10135. * Return true if the given x/y coordinates are within this Ellipse object.
  10136. * @method Phaser.Ellipse#contains
  10137. * @param {number} x - The X value of the coordinate to test.
  10138. * @param {number} y - The Y value of the coordinate to test.
  10139. * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
  10140. */
  10141. contains: function (x, y) {
  10142. return Phaser.Ellipse.contains(this, x, y);
  10143. },
  10144. /**
  10145. * Returns a string representation of this object.
  10146. * @method Phaser.Ellipse#toString
  10147. * @return {string} A string representation of the instance.
  10148. */
  10149. toString: function () {
  10150. return "[{Phaser.Ellipse (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + ")}]";
  10151. }
  10152. };
  10153. Phaser.Ellipse.prototype.constructor = Phaser.Ellipse;
  10154. /**
  10155. * The left coordinate of the Ellipse. The same as the X coordinate.
  10156. * @name Phaser.Ellipse#left
  10157. * @propety {number} left - Gets or sets the value of the leftmost point of the ellipse.
  10158. */
  10159. Object.defineProperty(Phaser.Ellipse.prototype, "left", {
  10160. get: function () {
  10161. return this.x;
  10162. },
  10163. set: function (value) {
  10164. this.x = value;
  10165. }
  10166. });
  10167. /**
  10168. * 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.
  10169. * @name Phaser.Ellipse#right
  10170. * @property {number} right - Gets or sets the value of the rightmost point of the ellipse.
  10171. */
  10172. Object.defineProperty(Phaser.Ellipse.prototype, "right", {
  10173. get: function () {
  10174. return this.x + this.width;
  10175. },
  10176. set: function (value) {
  10177. if (value < this.x)
  10178. {
  10179. this.width = 0;
  10180. }
  10181. else
  10182. {
  10183. this.width = this.x + value;
  10184. }
  10185. }
  10186. });
  10187. /**
  10188. * The top of the Ellipse. The same as its y property.
  10189. * @name Phaser.Ellipse#top
  10190. * @property {number} top - Gets or sets the top of the ellipse.
  10191. */
  10192. Object.defineProperty(Phaser.Ellipse.prototype, "top", {
  10193. get: function () {
  10194. return this.y;
  10195. },
  10196. set: function (value) {
  10197. this.y = value;
  10198. }
  10199. });
  10200. /**
  10201. * 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.
  10202. * @name Phaser.Ellipse#bottom
  10203. * @property {number} bottom - Gets or sets the bottom of the ellipse.
  10204. */
  10205. Object.defineProperty(Phaser.Ellipse.prototype, "bottom", {
  10206. get: function () {
  10207. return this.y + this.height;
  10208. },
  10209. set: function (value) {
  10210. if (value < this.y)
  10211. {
  10212. this.height = 0;
  10213. }
  10214. else
  10215. {
  10216. this.height = this.y + value;
  10217. }
  10218. }
  10219. });
  10220. /**
  10221. * 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.
  10222. * 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.
  10223. * @name Phaser.Ellipse#empty
  10224. * @property {boolean} empty - Gets or sets the empty state of the ellipse.
  10225. */
  10226. Object.defineProperty(Phaser.Ellipse.prototype, "empty", {
  10227. get: function () {
  10228. return (this.width === 0 || this.height === 0);
  10229. },
  10230. set: function (value) {
  10231. if (value === true)
  10232. {
  10233. this.setTo(0, 0, 0, 0);
  10234. }
  10235. }
  10236. });
  10237. /**
  10238. * Return true if the given x/y coordinates are within the Ellipse object.
  10239. * @method Phaser.Ellipse.contains
  10240. * @param {Phaser.Ellipse} a - The Ellipse to be checked.
  10241. * @param {number} x - The X value of the coordinate to test.
  10242. * @param {number} y - The Y value of the coordinate to test.
  10243. * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
  10244. */
  10245. Phaser.Ellipse.contains = function (a, x, y) {
  10246. if (a.width <= 0 || a.height <= 0)
  10247. {
  10248. return false;
  10249. }
  10250. // Normalize the coords to an ellipse with center 0,0 and a radius of 0.5
  10251. var normx = ((x - a.x) / a.width) - 0.5;
  10252. var normy = ((y - a.y) / a.height) - 0.5;
  10253. normx *= normx;
  10254. normy *= normy;
  10255. return (normx + normy < 0.25);
  10256. };
  10257. /**
  10258. * Returns the framing rectangle of the ellipse as a Phaser.Rectangle object.
  10259. *
  10260. * @method Phaser.Ellipse.getBounds
  10261. * @return {Phaser.Rectangle} The framing rectangle
  10262. */
  10263. Phaser.Ellipse.prototype.getBounds = function() {
  10264. return new Phaser.Rectangle(this.x, this.y, this.width, this.height);
  10265. };
  10266. // Because PIXI uses its own Ellipse, we'll replace it with ours to avoid duplicating code or confusion.
  10267. PIXI.Ellipse = Phaser.Ellipse;
  10268. /**
  10269. * @author Richard Davey <rich@photonstorm.com>
  10270. * @author Adrien Brault <adrien.brault@gmail.com>
  10271. * @copyright 2014 Photon Storm Ltd.
  10272. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10273. */
  10274. /**
  10275. * Creates a new Polygon. You have to provide a list of points.
  10276. * 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, ...],
  10277. * 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
  10278. * 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.
  10279. *
  10280. * @class Phaser.Polygon
  10281. * @classdesc The polygon represents a list of orderded points in space
  10282. * @constructor
  10283. * @param {Array<Phaser.Point>|Array<number>} points - The array of Points.
  10284. */
  10285. Phaser.Polygon = function (points) {
  10286. /**
  10287. * @property {number} type - The base object type.
  10288. */
  10289. this.type = Phaser.POLYGON;
  10290. //if points isn't an array, use arguments as the array
  10291. if (!(points instanceof Array))
  10292. {
  10293. points = Array.prototype.slice.call(arguments);
  10294. }
  10295. //if this is a flat array of numbers, convert it to points
  10296. if (typeof points[0] === 'number')
  10297. {
  10298. var p = [];
  10299. for (var i = 0, len = points.length; i < len; i += 2)
  10300. {
  10301. p.push(new Phaser.Point(points[i], points[i + 1]));
  10302. }
  10303. points = p;
  10304. }
  10305. /**
  10306. * @property {array<Phaser.Point>|array<number>} points - The array of Points.
  10307. */
  10308. this.points = points;
  10309. };
  10310. Phaser.Polygon.prototype = {
  10311. /**
  10312. * Creates a clone of this polygon.
  10313. *
  10314. * @method Phaser.Polygon#clone
  10315. * @return {Phaser.Polygon} A copy of the polygon.
  10316. */
  10317. clone: function () {
  10318. var points = [];
  10319. for (var i=0; i < this.points.length; i++)
  10320. {
  10321. points.push(this.points[i].clone());
  10322. }
  10323. return new Phaser.Polygon(points);
  10324. },
  10325. /**
  10326. * Checks whether the x and y coordinates are contained within this polygon.
  10327. *
  10328. * @method Phaser.Polygon#contains
  10329. * @param {number} x - The X value of the coordinate to test.
  10330. * @param {number} y - The Y value of the coordinate to test.
  10331. * @return {boolean} True if the coordinates are within this polygon, otherwise false.
  10332. */
  10333. contains: function (x, y) {
  10334. var inside = false;
  10335. // use some raycasting to test hits https://github.com/substack/point-in-polygon/blob/master/index.js
  10336. for (var i = 0, j = this.points.length - 1; i < this.points.length; j = i++)
  10337. {
  10338. var xi = this.points[i].x;
  10339. var yi = this.points[i].y;
  10340. var xj = this.points[j].x;
  10341. var yj = this.points[j].y;
  10342. var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  10343. if (intersect)
  10344. {
  10345. inside = true;
  10346. }
  10347. }
  10348. return inside;
  10349. }
  10350. };
  10351. Phaser.Polygon.prototype.constructor = Phaser.Polygon;
  10352. // Because PIXI uses its own Polygon, we'll replace it with ours to avoid duplicating code or confusion.
  10353. PIXI.Polygon = Phaser.Polygon;
  10354. /**
  10355. * @author Richard Davey <rich@photonstorm.com>
  10356. * @copyright 2014 Photon Storm Ltd.
  10357. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10358. */
  10359. /**
  10360. * 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.
  10361. * The game automatically creates a single Stage sized camera on boot. Move the camera around the world with Phaser.Camera.x/y
  10362. *
  10363. * @class Phaser.Camera
  10364. * @constructor
  10365. * @param {Phaser.Game} game - Game reference to the currently running game.
  10366. * @param {number} id - Not being used at the moment, will be when Phaser supports multiple camera
  10367. * @param {number} x - Position of the camera on the X axis
  10368. * @param {number} y - Position of the camera on the Y axis
  10369. * @param {number} width - The width of the view rectangle
  10370. * @param {number} height - The height of the view rectangle
  10371. */
  10372. Phaser.Camera = function (game, id, x, y, width, height) {
  10373. /**
  10374. * @property {Phaser.Game} game - A reference to the currently running Game.
  10375. */
  10376. this.game = game;
  10377. /**
  10378. * @property {Phaser.World} world - A reference to the game world.
  10379. */
  10380. this.world = game.world;
  10381. /**
  10382. * @property {number} id - Reserved for future multiple camera set-ups.
  10383. * @default
  10384. */
  10385. this.id = 0;
  10386. /**
  10387. * Camera view.
  10388. * The view into the world we wish to render (by default the game dimensions).
  10389. * The x/y values are in world coordinates, not screen coordinates, the width/height is how many pixels to render.
  10390. * Objects outside of this view are not rendered if set to camera cull.
  10391. * @property {Phaser.Rectangle} view
  10392. */
  10393. this.view = new Phaser.Rectangle(x, y, width, height);
  10394. /**
  10395. * @property {Phaser.Rectangle} screenView - Used by Sprites to work out Camera culling.
  10396. */
  10397. this.screenView = new Phaser.Rectangle(x, y, width, height);
  10398. /**
  10399. * 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.
  10400. * 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
  10401. * 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.
  10402. * @property {Phaser.Rectangle} bounds - The Rectangle in which the Camera is bounded. Set to null to allow for movement anywhere.
  10403. */
  10404. this.bounds = new Phaser.Rectangle(x, y, width, height);
  10405. /**
  10406. * @property {Phaser.Rectangle} deadzone - Moving inside this Rectangle will not cause camera moving.
  10407. */
  10408. this.deadzone = null;
  10409. /**
  10410. * @property {boolean} visible - Whether this camera is visible or not.
  10411. * @default
  10412. */
  10413. this.visible = true;
  10414. /**
  10415. * @property {boolean} atLimit - Whether this camera is flush with the World Bounds or not.
  10416. */
  10417. this.atLimit = { x: false, y: false };
  10418. /**
  10419. * @property {Phaser.Sprite} target - If the camera is tracking a Sprite, this is a reference to it, otherwise null.
  10420. * @default
  10421. */
  10422. this.target = null;
  10423. /**
  10424. * @property {number} edge - Edge property.
  10425. * @private
  10426. * @default
  10427. */
  10428. this._edge = 0;
  10429. /**
  10430. * @property {PIXI.DisplayObject} displayObject - The display object to which all game objects are added. Set by World.boot
  10431. */
  10432. this.displayObject = null;
  10433. /**
  10434. * @property {Phaser.Point} scale - The scale of the display object to which all game objects are added. Set by World.boot
  10435. */
  10436. this.scale = null;
  10437. };
  10438. /**
  10439. * @constant
  10440. * @type {number}
  10441. */
  10442. Phaser.Camera.FOLLOW_LOCKON = 0;
  10443. /**
  10444. * @constant
  10445. * @type {number}
  10446. */
  10447. Phaser.Camera.FOLLOW_PLATFORMER = 1;
  10448. /**
  10449. * @constant
  10450. * @type {number}
  10451. */
  10452. Phaser.Camera.FOLLOW_TOPDOWN = 2;
  10453. /**
  10454. * @constant
  10455. * @type {number}
  10456. */
  10457. Phaser.Camera.FOLLOW_TOPDOWN_TIGHT = 3;
  10458. Phaser.Camera.prototype = {
  10459. /**
  10460. * Tells this camera which sprite to follow.
  10461. * @method Phaser.Camera#follow
  10462. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text} target - The object you want the camera to track. Set to null to not follow anything.
  10463. * @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().
  10464. */
  10465. follow: function (target, style) {
  10466. if (typeof style === "undefined") { style = Phaser.Camera.FOLLOW_LOCKON; }
  10467. this.target = target;
  10468. var helper;
  10469. switch (style) {
  10470. case Phaser.Camera.FOLLOW_PLATFORMER:
  10471. var w = this.width / 8;
  10472. var h = this.height / 3;
  10473. this.deadzone = new Phaser.Rectangle((this.width - w) / 2, (this.height - h) / 2 - h * 0.25, w, h);
  10474. break;
  10475. case Phaser.Camera.FOLLOW_TOPDOWN:
  10476. helper = Math.max(this.width, this.height) / 4;
  10477. this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
  10478. break;
  10479. case Phaser.Camera.FOLLOW_TOPDOWN_TIGHT:
  10480. helper = Math.max(this.width, this.height) / 8;
  10481. this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
  10482. break;
  10483. case Phaser.Camera.FOLLOW_LOCKON:
  10484. this.deadzone = null;
  10485. break;
  10486. default:
  10487. this.deadzone = null;
  10488. break;
  10489. }
  10490. },
  10491. /**
  10492. * Move the camera focus on a display object instantly.
  10493. * @method Phaser.Camera#focusOn
  10494. * @param {any} displayObject - The display object to focus the camera on. Must have visible x/y properties.
  10495. */
  10496. focusOn: function (displayObject) {
  10497. this.setPosition(Math.round(displayObject.x - this.view.halfWidth), Math.round(displayObject.y - this.view.halfHeight));
  10498. },
  10499. /**
  10500. * Move the camera focus on a location instantly.
  10501. * @method Phaser.Camera#focusOnXY
  10502. * @param {number} x - X position.
  10503. * @param {number} y - Y position.
  10504. */
  10505. focusOnXY: function (x, y) {
  10506. this.setPosition(Math.round(x - this.view.halfWidth), Math.round(y - this.view.halfHeight));
  10507. },
  10508. /**
  10509. * Update focusing and scrolling.
  10510. * @method Phaser.Camera#update
  10511. */
  10512. update: function () {
  10513. if (this.target)
  10514. {
  10515. this.updateTarget();
  10516. }
  10517. if (this.bounds)
  10518. {
  10519. this.checkBounds();
  10520. }
  10521. this.displayObject.position.x = -this.view.x;
  10522. this.displayObject.position.y = -this.view.y;
  10523. },
  10524. /**
  10525. * Internal method
  10526. * @method Phaser.Camera#updateTarget
  10527. * @private
  10528. */
  10529. updateTarget: function () {
  10530. if (this.deadzone)
  10531. {
  10532. this._edge = this.target.x - this.deadzone.x;
  10533. if (this.view.x > this._edge)
  10534. {
  10535. this.view.x = this._edge;
  10536. }
  10537. this._edge = this.target.x + this.target.width - this.deadzone.x - this.deadzone.width;
  10538. if (this.view.x < this._edge)
  10539. {
  10540. this.view.x = this._edge;
  10541. }
  10542. this._edge = this.target.y - this.deadzone.y;
  10543. if (this.view.y > this._edge)
  10544. {
  10545. this.view.y = this._edge;
  10546. }
  10547. this._edge = this.target.y + this.target.height - this.deadzone.y - this.deadzone.height;
  10548. if (this.view.y < this._edge)
  10549. {
  10550. this.view.y = this._edge;
  10551. }
  10552. }
  10553. else
  10554. {
  10555. this.focusOnXY(this.target.x, this.target.y);
  10556. }
  10557. },
  10558. /**
  10559. * Update the Camera bounds to match the game world.
  10560. * @method Phaser.Camera#setBoundsToWorld
  10561. */
  10562. setBoundsToWorld: function () {
  10563. this.bounds.setTo(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height);
  10564. },
  10565. /**
  10566. * Method called to ensure the camera doesn't venture outside of the game world.
  10567. * @method Phaser.Camera#checkWorldBounds
  10568. */
  10569. checkBounds: function () {
  10570. this.atLimit.x = false;
  10571. this.atLimit.y = false;
  10572. // Make sure we didn't go outside the cameras bounds
  10573. if (this.view.x <= this.bounds.x)
  10574. {
  10575. this.atLimit.x = true;
  10576. this.view.x = this.bounds.x;
  10577. }
  10578. if (this.view.right >= this.bounds.right)
  10579. {
  10580. this.atLimit.x = true;
  10581. this.view.x = this.bounds.right - this.width;
  10582. }
  10583. if (this.view.y <= this.bounds.top)
  10584. {
  10585. this.atLimit.y = true;
  10586. this.view.y = this.bounds.top;
  10587. }
  10588. if (this.view.bottom >= this.bounds.bottom)
  10589. {
  10590. this.atLimit.y = true;
  10591. this.view.y = this.bounds.bottom - this.height;
  10592. }
  10593. this.view.floor();
  10594. },
  10595. /**
  10596. * A helper function to set both the X and Y properties of the camera at once
  10597. * without having to use game.camera.x and game.camera.y.
  10598. *
  10599. * @method Phaser.Camera#setPosition
  10600. * @param {number} x - X position.
  10601. * @param {number} y - Y position.
  10602. */
  10603. setPosition: function (x, y) {
  10604. this.view.x = x;
  10605. this.view.y = y;
  10606. if (this.bounds)
  10607. {
  10608. this.checkBounds();
  10609. }
  10610. },
  10611. /**
  10612. * Sets the size of the view rectangle given the width and height in parameters.
  10613. *
  10614. * @method Phaser.Camera#setSize
  10615. * @param {number} width - The desired width.
  10616. * @param {number} height - The desired height.
  10617. */
  10618. setSize: function (width, height) {
  10619. this.view.width = width;
  10620. this.view.height = height;
  10621. },
  10622. /**
  10623. * Resets the camera back to 0,0 and un-follows any object it may have been tracking.
  10624. *
  10625. * @method Phaser.Camera#reset
  10626. */
  10627. reset: function () {
  10628. this.target = null;
  10629. this.view.x = 0;
  10630. this.view.y = 0;
  10631. }
  10632. };
  10633. Phaser.Camera.prototype.constructor = Phaser.Camera;
  10634. /**
  10635. * The Cameras x coordinate. This value is automatically clamped if it falls outside of the World bounds.
  10636. * @name Phaser.Camera#x
  10637. * @property {number} x - Gets or sets the cameras x position.
  10638. */
  10639. Object.defineProperty(Phaser.Camera.prototype, "x", {
  10640. get: function () {
  10641. return this.view.x;
  10642. },
  10643. set: function (value) {
  10644. this.view.x = value;
  10645. if (this.bounds)
  10646. {
  10647. this.checkBounds();
  10648. }
  10649. }
  10650. });
  10651. /**
  10652. * The Cameras y coordinate. This value is automatically clamped if it falls outside of the World bounds.
  10653. * @name Phaser.Camera#y
  10654. * @property {number} y - Gets or sets the cameras y position.
  10655. */
  10656. Object.defineProperty(Phaser.Camera.prototype, "y", {
  10657. get: function () {
  10658. return this.view.y;
  10659. },
  10660. set: function (value) {
  10661. this.view.y = value;
  10662. if (this.bounds)
  10663. {
  10664. this.checkBounds();
  10665. }
  10666. }
  10667. });
  10668. /**
  10669. * The Cameras width. By default this is the same as the Game size and should not be adjusted for now.
  10670. * @name Phaser.Camera#width
  10671. * @property {number} width - Gets or sets the cameras width.
  10672. */
  10673. Object.defineProperty(Phaser.Camera.prototype, "width", {
  10674. get: function () {
  10675. return this.view.width;
  10676. },
  10677. set: function (value) {
  10678. this.view.width = value;
  10679. }
  10680. });
  10681. /**
  10682. * The Cameras height. By default this is the same as the Game size and should not be adjusted for now.
  10683. * @name Phaser.Camera#height
  10684. * @property {number} height - Gets or sets the cameras height.
  10685. */
  10686. Object.defineProperty(Phaser.Camera.prototype, "height", {
  10687. get: function () {
  10688. return this.view.height;
  10689. },
  10690. set: function (value) {
  10691. this.view.height = value;
  10692. }
  10693. });
  10694. /**
  10695. * @author Richard Davey <rich@photonstorm.com>
  10696. * @copyright 2014 Photon Storm Ltd.
  10697. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10698. */
  10699. /**
  10700. * This is a base State class which can be extended if you are creating your own game.
  10701. * It provides quick access to common functions such as the camera, cache, input, match, sound and more.
  10702. *
  10703. * @class Phaser.State
  10704. * @constructor
  10705. */
  10706. Phaser.State = function () {
  10707. /**
  10708. * @property {Phaser.Game} game - A reference to the currently running Game.
  10709. */
  10710. this.game = null;
  10711. /**
  10712. * @property {Phaser.GameObjectFactory} add - Reference to the GameObjectFactory.
  10713. */
  10714. this.add = null;
  10715. /**
  10716. * @property {Phaser.GameObjectCreator} make - Reference to the GameObjectCreator.
  10717. */
  10718. this.make = null;
  10719. /**
  10720. * @property {Phaser.Camera} camera - A handy reference to world.camera.
  10721. */
  10722. this.camera = null;
  10723. /**
  10724. * @property {Phaser.Cache} cache - Reference to the assets cache.
  10725. */
  10726. this.cache = null;
  10727. /**
  10728. * @property {Phaser.Input} input - Reference to the input manager
  10729. */
  10730. this.input = null;
  10731. /**
  10732. * @property {Phaser.Loader} load - Reference to the assets loader.
  10733. */
  10734. this.load = null;
  10735. /**
  10736. * @property {Phaser.Math} math - Reference to the math helper.
  10737. */
  10738. this.math = null;
  10739. /**
  10740. * @property {Phaser.SoundManager} sound - Reference to the sound manager.
  10741. */
  10742. this.sound = null;
  10743. /**
  10744. * @property {Phaser.ScaleManager} scale - Reference to the game scale manager.
  10745. */
  10746. this.scale = null;
  10747. /**
  10748. * @property {Phaser.Stage} stage - Reference to the stage.
  10749. */
  10750. this.stage = null;
  10751. /**
  10752. * @property {Phaser.Time} time - Reference to the core game clock.
  10753. */
  10754. this.time = null;
  10755. /**
  10756. * @property {Phaser.TweenManager} tweens - Reference to the tween manager.
  10757. */
  10758. this.tweens = null;
  10759. /**
  10760. * @property {Phaser.World} world - Reference to the world.
  10761. */
  10762. this.world = null;
  10763. /**
  10764. * @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.
  10765. */
  10766. this.particles = null;
  10767. /**
  10768. * @property {Phaser.Physics} physics - Reference to the physics manager.
  10769. */
  10770. this.physics = null;
  10771. /**
  10772. * @property {Phaser.RandomDataGenerator} rnd - Reference to the random data generator.
  10773. */
  10774. this.rnd = null;
  10775. };
  10776. Phaser.State.prototype = {
  10777. /**
  10778. * Override this method to add some load operations.
  10779. * If you need to use the loader, you may need to use them here.
  10780. *
  10781. * @method Phaser.State#preload
  10782. */
  10783. preload: function () {
  10784. },
  10785. /**
  10786. * Put update logic here.
  10787. *
  10788. * @method Phaser.State#loadUpdate
  10789. */
  10790. loadUpdate: function () {
  10791. },
  10792. /**
  10793. * Put render operations here.
  10794. *
  10795. * @method Phaser.State#loadRender
  10796. */
  10797. loadRender: function () {
  10798. },
  10799. /**
  10800. * This method is called after the game engine successfully switches states.
  10801. * Feel free to add any setup code here (do not load anything here, override preload() instead).
  10802. *
  10803. * @method Phaser.State#create
  10804. */
  10805. create: function () {
  10806. },
  10807. /**
  10808. * Put update logic here.
  10809. *
  10810. * @method Phaser.State#update
  10811. */
  10812. update: function () {
  10813. },
  10814. /**
  10815. * Put render operations here.
  10816. *
  10817. * @method Phaser.State#render
  10818. */
  10819. render: function () {
  10820. },
  10821. /**
  10822. * This method will be called when game paused.
  10823. *
  10824. * @method Phaser.State#paused
  10825. */
  10826. paused: function () {
  10827. },
  10828. /**
  10829. * This method will be called when the state is shut down (i.e. you switch to another state from this one).
  10830. * @method Phaser.State#shutdown
  10831. */
  10832. shutdown: function () {
  10833. }
  10834. };
  10835. Phaser.State.prototype.constructor = Phaser.State;
  10836. /* jshint newcap: false */
  10837. /**
  10838. * @author Richard Davey <rich@photonstorm.com>
  10839. * @copyright 2014 Photon Storm Ltd.
  10840. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10841. */
  10842. /**
  10843. * The State Manager is responsible for loading, setting up and switching game states.
  10844. *
  10845. * @class Phaser.StateManager
  10846. * @constructor
  10847. * @param {Phaser.Game} game - A reference to the currently running game.
  10848. * @param {Phaser.State|Object} [pendingState=null] - A State object to seed the manager with.
  10849. */
  10850. Phaser.StateManager = function (game, pendingState) {
  10851. /**
  10852. * @property {Phaser.Game} game - A reference to the currently running game.
  10853. */
  10854. this.game = game;
  10855. /**
  10856. * @property {Object} states - The object containing Phaser.States.
  10857. */
  10858. this.states = {};
  10859. /**
  10860. * @property {Phaser.State} _pendingState - The state to be switched to in the next frame.
  10861. * @private
  10862. */
  10863. this._pendingState = null;
  10864. if (typeof pendingState !== 'undefined' && pendingState !== null)
  10865. {
  10866. this._pendingState = pendingState;
  10867. }
  10868. /**
  10869. * @property {boolean} _clearWorld - Clear the world when we switch state?
  10870. * @private
  10871. */
  10872. this._clearWorld = false;
  10873. /**
  10874. * @property {boolean} _clearCache - Clear the cache when we switch state?
  10875. * @private
  10876. */
  10877. this._clearCache = false;
  10878. /**
  10879. * @property {boolean} _created - Flag that sets if the State has been created or not.
  10880. * @private
  10881. */
  10882. this._created = false;
  10883. /**
  10884. * @property {array} _args - Temporary container when you pass vars from one State to another.
  10885. * @private
  10886. */
  10887. this._args = [];
  10888. /**
  10889. * @property {string} current - The current active State object (defaults to null).
  10890. */
  10891. this.current = '';
  10892. /**
  10893. * @property {function} onInitCallback - This will be called when the state is started (i.e. set as the current active state).
  10894. */
  10895. this.onInitCallback = null;
  10896. /**
  10897. * @property {function} onPreloadCallback - This will be called when init states (loading assets...).
  10898. */
  10899. this.onPreloadCallback = null;
  10900. /**
  10901. * @property {function} onCreateCallback - This will be called when create states (setup states...).
  10902. */
  10903. this.onCreateCallback = null;
  10904. /**
  10905. * @property {function} onUpdateCallback - This will be called when State is updated, this doesn't happen during load (@see onLoadUpdateCallback).
  10906. */
  10907. this.onUpdateCallback = null;
  10908. /**
  10909. * @property {function} onRenderCallback - This will be called when the State is rendered, this doesn't happen during load (see onLoadRenderCallback).
  10910. */
  10911. this.onRenderCallback = null;
  10912. /**
  10913. * @property {function} onPreRenderCallback - This will be called before the State is rendered and before the stage is cleared.
  10914. */
  10915. this.onPreRenderCallback = null;
  10916. /**
  10917. * @property {function} onLoadUpdateCallback - This will be called when the State is updated but only during the load process.
  10918. */
  10919. this.onLoadUpdateCallback = null;
  10920. /**
  10921. * @property {function} onLoadRenderCallback - This will be called when the State is rendered but only during the load process.
  10922. */
  10923. this.onLoadRenderCallback = null;
  10924. /**
  10925. * @property {function} onPausedCallback - This will be called when the state is paused.
  10926. */
  10927. this.onPausedCallback = null;
  10928. /**
  10929. * @property {function} onResumedCallback - This will be called when the state is resumed from a paused state.
  10930. */
  10931. this.onResumedCallback = null;
  10932. /**
  10933. * @property {function} onShutDownCallback - This will be called when the state is shut down (i.e. swapped to another state).
  10934. */
  10935. this.onShutDownCallback = null;
  10936. };
  10937. Phaser.StateManager.prototype = {
  10938. /**
  10939. * The Boot handler is called by Phaser.Game when it first starts up.
  10940. * @method Phaser.StateManager#boot
  10941. * @private
  10942. */
  10943. boot: function () {
  10944. this.game.onPause.add(this.pause, this);
  10945. this.game.onResume.add(this.resume, this);
  10946. this.game.load.onLoadComplete.add(this.loadComplete, this);
  10947. if (this._pendingState !== null)
  10948. {
  10949. if (typeof this._pendingState === 'string')
  10950. {
  10951. // State was already added, so just start it
  10952. this.start(this._pendingState, false, false);
  10953. }
  10954. else
  10955. {
  10956. this.add('default', this._pendingState, true);
  10957. }
  10958. }
  10959. },
  10960. /**
  10961. * Adds a new State into the StateManager. You must give each State a unique key by which you'll identify it.
  10962. * The State can be either a Phaser.State object (or an object that extends it), a plain JavaScript object or a function.
  10963. * If a function is given a new state object will be created by calling it.
  10964. *
  10965. * @method Phaser.StateManager#add
  10966. * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
  10967. * @param {Phaser.State|object|function} state - The state you want to switch to.
  10968. * @param {boolean} [autoStart=false] - If true the State will be started immediately after adding it.
  10969. */
  10970. add: function (key, state, autoStart) {
  10971. if (typeof autoStart === "undefined") { autoStart = false; }
  10972. var newState;
  10973. if (state instanceof Phaser.State)
  10974. {
  10975. newState = state;
  10976. }
  10977. else if (typeof state === 'object')
  10978. {
  10979. newState = state;
  10980. newState.game = this.game;
  10981. }
  10982. else if (typeof state === 'function')
  10983. {
  10984. newState = new state(this.game);
  10985. }
  10986. this.states[key] = newState;
  10987. if (autoStart)
  10988. {
  10989. if (this.game.isBooted)
  10990. {
  10991. this.start(key);
  10992. }
  10993. else
  10994. {
  10995. this._pendingState = key;
  10996. }
  10997. }
  10998. return newState;
  10999. },
  11000. /**
  11001. * Delete the given state.
  11002. * @method Phaser.StateManager#remove
  11003. * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
  11004. */
  11005. remove: function (key) {
  11006. if (this.current === key)
  11007. {
  11008. this.callbackContext = null;
  11009. this.onInitCallback = null;
  11010. this.onShutDownCallback = null;
  11011. this.onPreloadCallback = null;
  11012. this.onLoadRenderCallback = null;
  11013. this.onLoadUpdateCallback = null;
  11014. this.onCreateCallback = null;
  11015. this.onUpdateCallback = null;
  11016. this.onRenderCallback = null;
  11017. this.onPausedCallback = null;
  11018. this.onResumedCallback = null;
  11019. this.onDestroyCallback = null;
  11020. }
  11021. delete this.states[key];
  11022. },
  11023. /**
  11024. * 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.
  11025. *
  11026. * @method Phaser.StateManager#start
  11027. * @param {string} key - The key of the state you want to start.
  11028. * @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)
  11029. * @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.
  11030. * @param {...*} parameter - Additional parameters that will be passed to the State.init function (if it has one).
  11031. */
  11032. start: function (key, clearWorld, clearCache) {
  11033. if (typeof clearWorld === "undefined") { clearWorld = true; }
  11034. if (typeof clearCache === "undefined") { clearCache = false; }
  11035. if (this.checkState(key))
  11036. {
  11037. // Place the state in the queue. It will be started the next time the game loop starts.
  11038. this._pendingState = key;
  11039. this._clearWorld = clearWorld;
  11040. this._clearCache = clearCache;
  11041. if (arguments.length > 3)
  11042. {
  11043. this._args = Array.prototype.splice.call(arguments, 3);
  11044. }
  11045. }
  11046. },
  11047. /**
  11048. * Restarts the current State. State.shutDown will be called (if it exists) before the State is restarted.
  11049. *
  11050. * @method Phaser.StateManager#restart
  11051. * @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)
  11052. * @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.
  11053. * @param {...*} parameter - Additional parameters that will be passed to the State.init function if it has one.
  11054. */
  11055. restart: function (clearWorld, clearCache) {
  11056. if (typeof clearWorld === "undefined") { clearWorld = true; }
  11057. if (typeof clearCache === "undefined") { clearCache = false; }
  11058. // Place the state in the queue. It will be started the next time the game loop starts.
  11059. this._pendingState = this.current;
  11060. this._clearWorld = clearWorld;
  11061. this._clearCache = clearCache;
  11062. if (arguments.length > 3)
  11063. {
  11064. this._args = Array.prototype.splice.call(arguments, 3);
  11065. }
  11066. },
  11067. /**
  11068. * Used by onInit and onShutdown when those functions don't exist on the state
  11069. * @method Phaser.StateManager#dummy
  11070. * @private
  11071. */
  11072. dummy: function () {
  11073. },
  11074. /**
  11075. * preUpdate is called right at the start of the game loop. It is responsible for changing to a new state that was requested previously.
  11076. *
  11077. * @method Phaser.StateManager#preUpdate
  11078. */
  11079. preUpdate: function () {
  11080. if (this._pendingState && this.game.isBooted)
  11081. {
  11082. // Already got a state running?
  11083. if (this.current)
  11084. {
  11085. this.onShutDownCallback.call(this.callbackContext, this.game);
  11086. this.game.tweens.removeAll();
  11087. this.game.camera.reset();
  11088. this.game.input.reset(true);
  11089. this.game.physics.clear();
  11090. this.game.time.removeAll();
  11091. if (this._clearWorld)
  11092. {
  11093. this.game.world.shutdown();
  11094. if (this._clearCache === true)
  11095. {
  11096. this.game.cache.destroy();
  11097. }
  11098. }
  11099. }
  11100. this.setCurrentState(this._pendingState);
  11101. if (this.onPreloadCallback)
  11102. {
  11103. this.game.load.reset();
  11104. this.onPreloadCallback.call(this.callbackContext, this.game);
  11105. // Is the loader empty?
  11106. if (this.game.load.totalQueuedFiles() === 0)
  11107. {
  11108. this.loadComplete();
  11109. }
  11110. else
  11111. {
  11112. // Start the loader going as we have something in the queue
  11113. this.game.load.start();
  11114. }
  11115. }
  11116. else
  11117. {
  11118. // No init? Then there was nothing to load either
  11119. this.loadComplete();
  11120. }
  11121. if (this.current === this._pendingState)
  11122. {
  11123. this._pendingState = null;
  11124. }
  11125. }
  11126. },
  11127. /**
  11128. * 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.
  11129. *
  11130. * @method Phaser.StateManager#checkState
  11131. * @param {string} key - The key of the state you want to check.
  11132. * @return {boolean} true if the State has the required functions, otherwise false.
  11133. */
  11134. checkState: function (key) {
  11135. if (this.states[key])
  11136. {
  11137. var valid = false;
  11138. if (this.states[key]['preload']) { valid = true; }
  11139. if (this.states[key]['create']) { valid = true; }
  11140. if (this.states[key]['update']) { valid = true; }
  11141. if (this.states[key]['render']) { valid = true; }
  11142. if (valid === false)
  11143. {
  11144. console.warn("Invalid Phaser State object given. Must contain at least a one of the required functions: preload, create, update or render");
  11145. return false;
  11146. }
  11147. return true;
  11148. }
  11149. else
  11150. {
  11151. console.warn("Phaser.StateManager - No state found with the key: " + key);
  11152. return false;
  11153. }
  11154. },
  11155. /**
  11156. * Links game properties to the State given by the key.
  11157. * @method Phaser.StateManager#link
  11158. * @param {string} key - State key.
  11159. * @protected
  11160. */
  11161. link: function (key) {
  11162. this.states[key].game = this.game;
  11163. this.states[key].add = this.game.add;
  11164. this.states[key].make = this.game.make;
  11165. this.states[key].camera = this.game.camera;
  11166. this.states[key].cache = this.game.cache;
  11167. this.states[key].input = this.game.input;
  11168. this.states[key].load = this.game.load;
  11169. this.states[key].math = this.game.math;
  11170. this.states[key].sound = this.game.sound;
  11171. this.states[key].scale = this.game.scale;
  11172. this.states[key].state = this;
  11173. this.states[key].stage = this.game.stage;
  11174. this.states[key].time = this.game.time;
  11175. this.states[key].tweens = this.game.tweens;
  11176. this.states[key].world = this.game.world;
  11177. this.states[key].particles = this.game.particles;
  11178. this.states[key].rnd = this.game.rnd;
  11179. this.states[key].physics = this.game.physics;
  11180. },
  11181. /**
  11182. * Sets the current State. Should not be called directly (use StateManager.start)
  11183. * @method Phaser.StateManager#setCurrentState
  11184. * @param {string} key - State key.
  11185. * @private
  11186. */
  11187. setCurrentState: function (key) {
  11188. this.callbackContext = this.states[key];
  11189. this.link(key);
  11190. // Used when the state is set as being the current active state
  11191. this.onInitCallback = this.states[key]['init'] || this.dummy;
  11192. this.onPreloadCallback = this.states[key]['preload'] || null;
  11193. this.onLoadRenderCallback = this.states[key]['loadRender'] || null;
  11194. this.onLoadUpdateCallback = this.states[key]['loadUpdate'] || null;
  11195. this.onCreateCallback = this.states[key]['create'] || null;
  11196. this.onUpdateCallback = this.states[key]['update'] || null;
  11197. this.onPreRenderCallback = this.states[key]['preRender'] || null;
  11198. this.onRenderCallback = this.states[key]['render'] || null;
  11199. this.onPausedCallback = this.states[key]['paused'] || null;
  11200. this.onResumedCallback = this.states[key]['resumed'] || null;
  11201. // Used when the state is no longer the current active state
  11202. this.onShutDownCallback = this.states[key]['shutdown'] || this.dummy;
  11203. this.current = key;
  11204. this._created = false;
  11205. this.onInitCallback.apply(this.callbackContext, this._args);
  11206. this._args = [];
  11207. },
  11208. /**
  11209. * Gets the current State.
  11210. *
  11211. * @method Phaser.StateManager#getCurrentState
  11212. * @return Phaser.State
  11213. * @public
  11214. */
  11215. getCurrentState: function() {
  11216. return this.states[this.current];
  11217. },
  11218. /**
  11219. * @method Phaser.StateManager#loadComplete
  11220. * @protected
  11221. */
  11222. loadComplete: function () {
  11223. if (this._created === false && this.onCreateCallback)
  11224. {
  11225. this._created = true;
  11226. this.onCreateCallback.call(this.callbackContext, this.game);
  11227. }
  11228. else
  11229. {
  11230. this._created = true;
  11231. }
  11232. },
  11233. /**
  11234. * @method Phaser.StateManager#pause
  11235. * @protected
  11236. */
  11237. pause: function () {
  11238. if (this._created && this.onPausedCallback)
  11239. {
  11240. this.onPausedCallback.call(this.callbackContext, this.game);
  11241. }
  11242. },
  11243. /**
  11244. * @method Phaser.StateManager#resume
  11245. * @protected
  11246. */
  11247. resume: function () {
  11248. if (this._created && this.onResumedCallback)
  11249. {
  11250. this.onResumedCallback.call(this.callbackContext, this.game);
  11251. }
  11252. },
  11253. /**
  11254. * @method Phaser.StateManager#update
  11255. * @protected
  11256. */
  11257. update: function () {
  11258. if (this._created && this.onUpdateCallback)
  11259. {
  11260. this.onUpdateCallback.call(this.callbackContext, this.game);
  11261. }
  11262. else
  11263. {
  11264. if (this.onLoadUpdateCallback)
  11265. {
  11266. this.onLoadUpdateCallback.call(this.callbackContext, this.game);
  11267. }
  11268. }
  11269. },
  11270. /**
  11271. * @method Phaser.StateManager#preRender
  11272. * @protected
  11273. */
  11274. preRender: function () {
  11275. if (this.onPreRenderCallback)
  11276. {
  11277. this.onPreRenderCallback.call(this.callbackContext, this.game);
  11278. }
  11279. },
  11280. /**
  11281. * @method Phaser.StateManager#render
  11282. * @protected
  11283. */
  11284. render: function () {
  11285. if (this._created && this.onRenderCallback)
  11286. {
  11287. if (this.game.renderType === Phaser.CANVAS)
  11288. {
  11289. this.game.context.save();
  11290. this.game.context.setTransform(1, 0, 0, 1, 0, 0);
  11291. }
  11292. this.onRenderCallback.call(this.callbackContext, this.game);
  11293. if (this.game.renderType === Phaser.CANVAS)
  11294. {
  11295. this.game.context.restore();
  11296. }
  11297. }
  11298. else
  11299. {
  11300. if (this.onLoadRenderCallback)
  11301. {
  11302. this.onLoadRenderCallback.call(this.callbackContext, this.game);
  11303. }
  11304. }
  11305. },
  11306. /**
  11307. * Removes all StateManager callback references to the State object, nulls the game reference and clears the States object.
  11308. * You don't recover from this without rebuilding the Phaser instance again.
  11309. * @method Phaser.StateManager#destroy
  11310. */
  11311. destroy: function () {
  11312. this.callbackContext = null;
  11313. this.onInitCallback = null;
  11314. this.onShutDownCallback = null;
  11315. this.onPreloadCallback = null;
  11316. this.onLoadRenderCallback = null;
  11317. this.onLoadUpdateCallback = null;
  11318. this.onCreateCallback = null;
  11319. this.onUpdateCallback = null;
  11320. this.onRenderCallback = null;
  11321. this.onPausedCallback = null;
  11322. this.onResumedCallback = null;
  11323. this.onDestroyCallback = null;
  11324. this.game = null;
  11325. this.states = {};
  11326. this._pendingState = null;
  11327. }
  11328. };
  11329. Phaser.StateManager.prototype.constructor = Phaser.StateManager;
  11330. /**
  11331. * @author Richard Davey <rich@photonstorm.com>
  11332. * @copyright 2014 Photon Storm Ltd.
  11333. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11334. */
  11335. /**
  11336. * A basic linked list data structure.
  11337. *
  11338. * @class Phaser.LinkedList
  11339. * @constructor
  11340. */
  11341. Phaser.LinkedList = function () {
  11342. /**
  11343. * @property {object} next - Next element in the list.
  11344. * @default
  11345. */
  11346. this.next = null;
  11347. /**
  11348. * @property {object} prev - Previous element in the list.
  11349. * @default
  11350. */
  11351. this.prev = null;
  11352. /**
  11353. * @property {object} first - First element in the list.
  11354. * @default
  11355. */
  11356. this.first = null;
  11357. /**
  11358. * @property {object} last - Last element in the list.
  11359. * @default
  11360. */
  11361. this.last = null;
  11362. /**
  11363. * @property {object} game - Number of elements in the list.
  11364. * @default
  11365. */
  11366. this.total = 0;
  11367. };
  11368. Phaser.LinkedList.prototype = {
  11369. /**
  11370. * Adds a new element to this linked list.
  11371. *
  11372. * @method Phaser.LinkedList#add
  11373. * @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.
  11374. * @return {object} The child that was added.
  11375. */
  11376. add: function (child) {
  11377. // If the list is empty
  11378. if (this.total === 0 && this.first == null && this.last == null)
  11379. {
  11380. this.first = child;
  11381. this.last = child;
  11382. this.next = child;
  11383. child.prev = this;
  11384. this.total++;
  11385. return child;
  11386. }
  11387. // 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)
  11388. this.last.next = child;
  11389. child.prev = this.last;
  11390. this.last = child;
  11391. this.total++;
  11392. return child;
  11393. },
  11394. /**
  11395. * Removes the given element from this linked list if it exists.
  11396. *
  11397. * @method Phaser.LinkedList#remove
  11398. * @param {object} child - The child to be removed from the list.
  11399. */
  11400. remove: function (child) {
  11401. if (child == this.first)
  11402. {
  11403. // It was 'first', make 'first' point to first.next
  11404. this.first = this.first.next;
  11405. }
  11406. else if (child == this.last)
  11407. {
  11408. // It was 'last', make 'last' point to last.prev
  11409. this.last = this.last.prev;
  11410. }
  11411. if (child.prev)
  11412. {
  11413. // make child.prev.next point to childs.next instead of child
  11414. child.prev.next = child.next;
  11415. }
  11416. if (child.next)
  11417. {
  11418. // make child.next.prev point to child.prev instead of child
  11419. child.next.prev = child.prev;
  11420. }
  11421. child.next = child.prev = null;
  11422. if (this.first == null )
  11423. {
  11424. this.last = null;
  11425. }
  11426. this.total--;
  11427. },
  11428. /**
  11429. * Calls a function on all members of this list, using the member as the context for the callback.
  11430. * The function must exist on the member.
  11431. *
  11432. * @method Phaser.LinkedList#callAll
  11433. * @param {function} callback - The function to call.
  11434. */
  11435. callAll: function (callback) {
  11436. if (!this.first || !this.last)
  11437. {
  11438. return;
  11439. }
  11440. var entity = this.first;
  11441. do
  11442. {
  11443. if (entity && entity[callback])
  11444. {
  11445. entity[callback].call(entity);
  11446. }
  11447. entity = entity.next;
  11448. }
  11449. while(entity != this.last.next);
  11450. }
  11451. };
  11452. Phaser.LinkedList.prototype.constructor = Phaser.LinkedList;
  11453. /**
  11454. * @author Richard Davey <rich@photonstorm.com>
  11455. * @copyright 2014 Photon Storm Ltd.
  11456. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11457. */
  11458. /**
  11459. * @class Phaser.Signal
  11460. * @classdesc A Signal is used for object communication via a custom broadcaster instead of Events.
  11461. * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
  11462. * @constructor
  11463. */
  11464. Phaser.Signal = function () {
  11465. /**
  11466. * @property {Array.<Phaser.SignalBinding>} _bindings - Internal variable.
  11467. * @private
  11468. */
  11469. this._bindings = [];
  11470. /**
  11471. * @property {any} _prevParams - Internal variable.
  11472. * @private
  11473. */
  11474. this._prevParams = null;
  11475. // enforce dispatch to aways work on same context (#47)
  11476. var self = this;
  11477. /**
  11478. * @property {function} dispatch - The dispatch function is what sends the Signal out.
  11479. */
  11480. this.dispatch = function(){
  11481. Phaser.Signal.prototype.dispatch.apply(self, arguments);
  11482. };
  11483. };
  11484. Phaser.Signal.prototype = {
  11485. /**
  11486. * If Signal should keep record of previously dispatched parameters and
  11487. * automatically execute listener during `add()`/`addOnce()` if Signal was
  11488. * already dispatched before.
  11489. * @property {boolean} memorize
  11490. */
  11491. memorize: false,
  11492. /**
  11493. * @property {boolean} _shouldPropagate
  11494. * @private
  11495. */
  11496. _shouldPropagate: true,
  11497. /**
  11498. * If Signal is active and should broadcast events.
  11499. * <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>
  11500. * @property {boolean} active
  11501. * @default
  11502. */
  11503. active: true,
  11504. /**
  11505. * @method Phaser.Signal#validateListener
  11506. * @param {function} listener - Signal handler function.
  11507. * @param {string} fnName - Function name.
  11508. * @private
  11509. */
  11510. validateListener: function (listener, fnName) {
  11511. if (typeof listener !== 'function') {
  11512. throw new Error('listener is a required param of {fn}() and should be a Function.'.replace('{fn}', fnName));
  11513. }
  11514. },
  11515. /**
  11516. * @method Phaser.Signal#_registerListener
  11517. * @param {function} listener - Signal handler function.
  11518. * @param {boolean} isOnce - Description.
  11519. * @param {object} [listenerContext] - Description.
  11520. * @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).
  11521. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  11522. * @private
  11523. */
  11524. _registerListener: function (listener, isOnce, listenerContext, priority) {
  11525. var prevIndex = this._indexOfListener(listener, listenerContext),
  11526. binding;
  11527. if (prevIndex !== -1) {
  11528. binding = this._bindings[prevIndex];
  11529. if (binding.isOnce() !== isOnce) {
  11530. throw new Error('You cannot add' + (isOnce ? '' : 'Once') + '() then add' + (!isOnce ? '' : 'Once') + '() the same listener without removing the relationship first.');
  11531. }
  11532. } else {
  11533. binding = new Phaser.SignalBinding(this, listener, isOnce, listenerContext, priority);
  11534. this._addBinding(binding);
  11535. }
  11536. if (this.memorize && this._prevParams) {
  11537. binding.execute(this._prevParams);
  11538. }
  11539. return binding;
  11540. },
  11541. /**
  11542. * @method Phaser.Signal#_addBinding
  11543. * @param {Phaser.SignalBinding} binding - An Object representing the binding between the Signal and listener.
  11544. * @private
  11545. */
  11546. _addBinding: function (binding) {
  11547. //simplified insertion sort
  11548. var n = this._bindings.length;
  11549. do { --n; } while (this._bindings[n] && binding._priority <= this._bindings[n]._priority);
  11550. this._bindings.splice(n + 1, 0, binding);
  11551. },
  11552. /**
  11553. * @method Phaser.Signal#_indexOfListener
  11554. * @param {function} listener - Signal handler function.
  11555. * @return {number} Description.
  11556. * @private
  11557. */
  11558. _indexOfListener: function (listener, context) {
  11559. var n = this._bindings.length,
  11560. cur;
  11561. while (n--) {
  11562. cur = this._bindings[n];
  11563. if (cur._listener === listener && cur.context === context) {
  11564. return n;
  11565. }
  11566. }
  11567. return -1;
  11568. },
  11569. /**
  11570. * Check if listener was attached to Signal.
  11571. *
  11572. * @method Phaser.Signal#has
  11573. * @param {Function} listener - Signal handler function.
  11574. * @param {Object} [context] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  11575. * @return {boolean} If Signal has the specified listener.
  11576. */
  11577. has: function (listener, context) {
  11578. return this._indexOfListener(listener, context) !== -1;
  11579. },
  11580. /**
  11581. * Add a listener to the signal.
  11582. *
  11583. * @method Phaser.Signal#add
  11584. * @param {function} listener - Signal handler function.
  11585. * @param {object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  11586. * @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).
  11587. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  11588. */
  11589. add: function (listener, listenerContext, priority) {
  11590. this.validateListener(listener, 'add');
  11591. return this._registerListener(listener, false, listenerContext, priority);
  11592. },
  11593. /**
  11594. * Add listener to the signal that should be removed after first execution (will be executed only once).
  11595. *
  11596. * @method Phaser.Signal#addOnce
  11597. * @param {function} listener Signal handler function.
  11598. * @param {object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  11599. * @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)
  11600. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  11601. */
  11602. addOnce: function (listener, listenerContext, priority) {
  11603. this.validateListener(listener, 'addOnce');
  11604. return this._registerListener(listener, true, listenerContext, priority);
  11605. },
  11606. /**
  11607. * Remove a single listener from the dispatch queue.
  11608. *
  11609. * @method Phaser.Signal#remove
  11610. * @param {function} listener Handler function that should be removed.
  11611. * @param {object} [context] Execution context (since you can add the same handler multiple times if executing in a different context).
  11612. * @return {function} Listener handler function.
  11613. */
  11614. remove: function (listener, context) {
  11615. this.validateListener(listener, 'remove');
  11616. var i = this._indexOfListener(listener, context);
  11617. if (i !== -1)
  11618. {
  11619. this._bindings[i]._destroy(); //no reason to a Phaser.SignalBinding exist if it isn't attached to a signal
  11620. this._bindings.splice(i, 1);
  11621. }
  11622. return listener;
  11623. },
  11624. /**
  11625. * Remove all listeners from the Signal.
  11626. *
  11627. * @method Phaser.Signal#removeAll
  11628. */
  11629. removeAll: function () {
  11630. var n = this._bindings.length;
  11631. while (n--) {
  11632. this._bindings[n]._destroy();
  11633. }
  11634. this._bindings.length = 0;
  11635. },
  11636. /**
  11637. * Gets the total number of listeneres attached to ths Signal.
  11638. *
  11639. * @method Phaser.Signal#getNumListeners
  11640. * @return {number} Number of listeners attached to the Signal.
  11641. */
  11642. getNumListeners: function () {
  11643. return this._bindings.length;
  11644. },
  11645. /**
  11646. * Stop propagation of the event, blocking the dispatch to next listeners on the queue.
  11647. * IMPORTANT: should be called only during signal dispatch, calling it before/after dispatch won't affect signal broadcast.
  11648. * @see Signal.prototype.disable
  11649. *
  11650. * @method Phaser.Signal#halt
  11651. */
  11652. halt: function () {
  11653. this._shouldPropagate = false;
  11654. },
  11655. /**
  11656. * Dispatch/Broadcast Signal to all listeners added to the queue.
  11657. *
  11658. * @method Phaser.Signal#dispatch
  11659. * @param {any} [params] - Parameters that should be passed to each handler.
  11660. */
  11661. dispatch: function () {
  11662. if (!this.active)
  11663. {
  11664. return;
  11665. }
  11666. var paramsArr = Array.prototype.slice.call(arguments);
  11667. var n = this._bindings.length;
  11668. var bindings;
  11669. if (this.memorize)
  11670. {
  11671. this._prevParams = paramsArr;
  11672. }
  11673. if (!n)
  11674. {
  11675. // Should come after memorize
  11676. return;
  11677. }
  11678. bindings = this._bindings.slice(); //clone array in case add/remove items during dispatch
  11679. this._shouldPropagate = true; //in case `halt` was called before dispatch or during the previous dispatch.
  11680. //execute all callbacks until end of the list or until a callback returns `false` or stops propagation
  11681. //reverse loop since listeners with higher priority will be added at the end of the list
  11682. do { n--; } while (bindings[n] && this._shouldPropagate && bindings[n].execute(paramsArr) !== false);
  11683. },
  11684. /**
  11685. * Forget memorized arguments.
  11686. * @see Signal.memorize
  11687. *
  11688. * @method Phaser.Signal#forget
  11689. */
  11690. forget: function(){
  11691. this._prevParams = null;
  11692. },
  11693. /**
  11694. * Remove all bindings from signal and destroy any reference to external objects (destroy Signal object).
  11695. * IMPORTANT: calling any method on the signal instance after calling dispose will throw errors.
  11696. *
  11697. * @method Phaser.Signal#dispose
  11698. */
  11699. dispose: function () {
  11700. this.removeAll();
  11701. delete this._bindings;
  11702. delete this._prevParams;
  11703. },
  11704. /**
  11705. *
  11706. * @method Phaser.Signal#toString
  11707. * @return {string} String representation of the object.
  11708. */
  11709. toString: function () {
  11710. return '[Phaser.Signal active:'+ this.active +' numListeners:'+ this.getNumListeners() +']';
  11711. }
  11712. };
  11713. Phaser.Signal.prototype.constructor = Phaser.Signal;
  11714. /**
  11715. * @author Richard Davey <rich@photonstorm.com>
  11716. * @copyright 2014 Photon Storm Ltd.
  11717. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11718. */
  11719. /**
  11720. * @class Phaser.SignalBinding
  11721. * @classdesc Object that represents a binding between a Signal and a listener function.
  11722. * This is an internal constructor and shouldn't be called by regular users.
  11723. * Inspired by Joa Ebert AS3 SignalBinding and Robert Penner's Slot classes.
  11724. *
  11725. * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
  11726. * @constructor
  11727. * @param {Phaser.Signal} signal - Reference to Signal object that listener is currently bound to.
  11728. * @param {function} listener - Handler function bound to the signal.
  11729. * @param {boolean} isOnce - If binding should be executed just once.
  11730. * @param {object} [listenerContext] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  11731. * @param {number} [priority] - The priority level of the event listener. (default = 0).
  11732. */
  11733. Phaser.SignalBinding = function (signal, listener, isOnce, listenerContext, priority) {
  11734. /**
  11735. * @property {Phaser.Game} _listener - Handler function bound to the signal.
  11736. * @private
  11737. */
  11738. this._listener = listener;
  11739. /**
  11740. * @property {boolean} _isOnce - If binding should be executed just once.
  11741. * @private
  11742. */
  11743. this._isOnce = isOnce;
  11744. /**
  11745. * @property {object|undefined|null} context - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  11746. */
  11747. this.context = listenerContext;
  11748. /**
  11749. * @property {Phaser.Signal} _signal - Reference to Signal object that listener is currently bound to.
  11750. * @private
  11751. */
  11752. this._signal = signal;
  11753. /**
  11754. * @property {number} _priority - Listener priority.
  11755. * @private
  11756. */
  11757. this._priority = priority || 0;
  11758. };
  11759. Phaser.SignalBinding.prototype = {
  11760. /**
  11761. * If binding is active and should be executed.
  11762. * @property {boolean} active
  11763. * @default
  11764. */
  11765. active: true,
  11766. /**
  11767. * Default parameters passed to listener during `Signal.dispatch` and `SignalBinding.execute` (curried parameters).
  11768. * @property {array|null} params
  11769. * @default
  11770. */
  11771. params: null,
  11772. /**
  11773. * Call listener passing arbitrary parameters.
  11774. * 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.
  11775. * @method Phaser.SignalBinding#execute
  11776. * @param {array} [paramsArr] - Array of parameters that should be passed to the listener.
  11777. * @return {any} Value returned by the listener.
  11778. */
  11779. execute: function(paramsArr) {
  11780. var handlerReturn, params;
  11781. if (this.active && !!this._listener)
  11782. {
  11783. params = this.params ? this.params.concat(paramsArr) : paramsArr;
  11784. handlerReturn = this._listener.apply(this.context, params);
  11785. if (this._isOnce)
  11786. {
  11787. this.detach();
  11788. }
  11789. }
  11790. return handlerReturn;
  11791. },
  11792. /**
  11793. * Detach binding from signal.
  11794. * alias to: @see mySignal.remove(myBinding.getListener());
  11795. * @method Phaser.SignalBinding#detach
  11796. * @return {function|null} Handler function bound to the signal or `null` if binding was previously detached.
  11797. */
  11798. detach: function () {
  11799. return this.isBound() ? this._signal.remove(this._listener, this.context) : null;
  11800. },
  11801. /**
  11802. * @method Phaser.SignalBinding#isBound
  11803. * @return {boolean} True if binding is still bound to the signal and has a listener.
  11804. */
  11805. isBound: function () {
  11806. return (!!this._signal && !!this._listener);
  11807. },
  11808. /**
  11809. * @method Phaser.SignalBinding#isOnce
  11810. * @return {boolean} If SignalBinding will only be executed once.
  11811. */
  11812. isOnce: function () {
  11813. return this._isOnce;
  11814. },
  11815. /**
  11816. * @method Phaser.SignalBinding#getListener
  11817. * @return {Function} Handler function bound to the signal.
  11818. */
  11819. getListener: function () {
  11820. return this._listener;
  11821. },
  11822. /**
  11823. * @method Phaser.SignalBinding#getSignal
  11824. * @return {Signal} Signal that listener is currently bound to.
  11825. */
  11826. getSignal: function () {
  11827. return this._signal;
  11828. },
  11829. /**
  11830. * @method Phaser.SignalBinding#_destroy
  11831. * Delete instance properties
  11832. * @private
  11833. */
  11834. _destroy: function () {
  11835. delete this._signal;
  11836. delete this._listener;
  11837. delete this.context;
  11838. },
  11839. /**
  11840. * @method Phaser.SignalBinding#toString
  11841. * @return {string} String representation of the object.
  11842. */
  11843. toString: function () {
  11844. return '[Phaser.SignalBinding isOnce:' + this._isOnce +', isBound:'+ this.isBound() +', active:' + this.active + ']';
  11845. }
  11846. };
  11847. Phaser.SignalBinding.prototype.constructor = Phaser.SignalBinding;
  11848. /**
  11849. * @author Richard Davey <rich@photonstorm.com>
  11850. * @copyright 2014 Photon Storm Ltd.
  11851. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11852. */
  11853. /**
  11854. * This is a base Filter template to use for any Phaser filter development.
  11855. *
  11856. * @class Phaser.Filter
  11857. * @classdesc Phaser - Filter
  11858. * @constructor
  11859. * @param {Phaser.Game} game - A reference to the currently running game.
  11860. * @param {Object} uniforms - Uniform mappings object
  11861. * @param {Array} fragmentSrc - The fragment shader code.
  11862. */
  11863. Phaser.Filter = function (game, uniforms, fragmentSrc) {
  11864. /**
  11865. * @property {Phaser.Game} game - A reference to the currently running game.
  11866. */
  11867. this.game = game;
  11868. /**
  11869. * @property {number} type - The const type of this object, either Phaser.WEBGL_FILTER or Phaser.CANVAS_FILTER.
  11870. * @default
  11871. */
  11872. this.type = Phaser.WEBGL_FILTER;
  11873. /**
  11874. * An array of passes - some filters contain a few steps this array simply stores the steps in a linear fashion.
  11875. * For example the blur filter has two passes blurX and blurY.
  11876. * @property {array} passes - An array of filter objects.
  11877. * @private
  11878. */
  11879. this.passes = [this];
  11880. /**
  11881. * @property {array} shaders - Array an array of shaders.
  11882. * @private
  11883. */
  11884. this.shaders = [];
  11885. /**
  11886. * @property {boolean} dirty - Internal PIXI var.
  11887. * @default
  11888. */
  11889. this.dirty = true;
  11890. /**
  11891. * @property {number} padding - Internal PIXI var.
  11892. * @default
  11893. */
  11894. this.padding = 0;
  11895. /**
  11896. * @property {object} uniforms - Default uniform mappings.
  11897. */
  11898. this.uniforms = {
  11899. time: { type: '1f', value: 0 },
  11900. resolution: { type: '2f', value: { x: 256, y: 256 }},
  11901. mouse: { type: '2f', value: { x: 0.0, y: 0.0 }}
  11902. };
  11903. /**
  11904. * @property {array} fragmentSrc - The fragment shader code.
  11905. */
  11906. this.fragmentSrc = fragmentSrc || [];
  11907. };
  11908. Phaser.Filter.prototype = {
  11909. /**
  11910. * Should be over-ridden.
  11911. * @method Phaser.Filter#init
  11912. */
  11913. init: function () {
  11914. // This should be over-ridden. Will receive a variable number of arguments.
  11915. },
  11916. /**
  11917. * Set the resolution uniforms on the filter.
  11918. * @method Phaser.Filter#setResolution
  11919. * @param {number} width - The width of the display.
  11920. * @param {number} height - The height of the display.
  11921. */
  11922. setResolution: function (width, height) {
  11923. this.uniforms.resolution.value.x = width;
  11924. this.uniforms.resolution.value.y = height;
  11925. },
  11926. /**
  11927. * Updates the filter.
  11928. * @method Phaser.Filter#update
  11929. * @param {Phaser.Pointer} [pointer] - A Pointer object to use for the filter. The coordinates are mapped to the mouse uniform.
  11930. */
  11931. update: function (pointer) {
  11932. if (typeof pointer !== 'undefined')
  11933. {
  11934. if (pointer.x > 0)
  11935. {
  11936. this.uniforms.mouse.x = pointer.x.toFixed(2);
  11937. }
  11938. if (pointer.y > 0)
  11939. {
  11940. this.uniforms.mouse.y = pointer.y.toFixed(2);
  11941. }
  11942. }
  11943. this.uniforms.time.value = this.game.time.totalElapsedSeconds();
  11944. },
  11945. /**
  11946. * Clear down this Filter and null out references
  11947. * @method Phaser.Filter#destroy
  11948. */
  11949. destroy: function () {
  11950. this.game = null;
  11951. }
  11952. };
  11953. Phaser.Filter.prototype.constructor = Phaser.Filter;
  11954. /**
  11955. * @name Phaser.Filter#width
  11956. * @property {number} width - The width (resolution uniform)
  11957. */
  11958. Object.defineProperty(Phaser.Filter.prototype, 'width', {
  11959. get: function() {
  11960. return this.uniforms.resolution.value.x;
  11961. },
  11962. set: function(value) {
  11963. this.uniforms.resolution.value.x = value;
  11964. }
  11965. });
  11966. /**
  11967. * @name Phaser.Filter#height
  11968. * @property {number} height - The height (resolution uniform)
  11969. */
  11970. Object.defineProperty(Phaser.Filter.prototype, 'height', {
  11971. get: function() {
  11972. return this.uniforms.resolution.value.y;
  11973. },
  11974. set: function(value) {
  11975. this.uniforms.resolution.value.y = value;
  11976. }
  11977. });
  11978. /**
  11979. * @author Richard Davey <rich@photonstorm.com>
  11980. * @copyright 2014 Photon Storm Ltd.
  11981. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11982. */
  11983. /**
  11984. * This is a base Plugin template to use for any Phaser plugin development.
  11985. *
  11986. * @class Phaser.Plugin
  11987. * @classdesc Phaser - Plugin
  11988. * @constructor
  11989. * @param {Phaser.Game} game - A reference to the currently running game.
  11990. * @param {Any} parent - The object that owns this plugin, usually Phaser.PluginManager.
  11991. */
  11992. Phaser.Plugin = function (game, parent) {
  11993. if (typeof parent === 'undefined') { parent = null; }
  11994. /**
  11995. * @property {Phaser.Game} game - A reference to the currently running game.
  11996. */
  11997. this.game = game;
  11998. /**
  11999. * @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.
  12000. */
  12001. this.parent = parent;
  12002. /**
  12003. * @property {boolean} active - A Plugin with active=true has its preUpdate and update methods called by the parent, otherwise they are skipped.
  12004. * @default
  12005. */
  12006. this.active = false;
  12007. /**
  12008. * @property {boolean} visible - A Plugin with visible=true has its render and postRender methods called by the parent, otherwise they are skipped.
  12009. * @default
  12010. */
  12011. this.visible = false;
  12012. /**
  12013. * @property {boolean} hasPreUpdate - A flag to indicate if this plugin has a preUpdate method.
  12014. * @default
  12015. */
  12016. this.hasPreUpdate = false;
  12017. /**
  12018. * @property {boolean} hasUpdate - A flag to indicate if this plugin has an update method.
  12019. * @default
  12020. */
  12021. this.hasUpdate = false;
  12022. /**
  12023. * @property {boolean} hasPostUpdate - A flag to indicate if this plugin has a postUpdate method.
  12024. * @default
  12025. */
  12026. this.hasPostUpdate = false;
  12027. /**
  12028. * @property {boolean} hasRender - A flag to indicate if this plugin has a render method.
  12029. * @default
  12030. */
  12031. this.hasRender = false;
  12032. /**
  12033. * @property {boolean} hasPostRender - A flag to indicate if this plugin has a postRender method.
  12034. * @default
  12035. */
  12036. this.hasPostRender = false;
  12037. };
  12038. Phaser.Plugin.prototype = {
  12039. /**
  12040. * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
  12041. * It is only called if active is set to true.
  12042. * @method Phaser.Plugin#preUpdate
  12043. */
  12044. preUpdate: function () {
  12045. },
  12046. /**
  12047. * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
  12048. * It is only called if active is set to true.
  12049. * @method Phaser.Plugin#update
  12050. */
  12051. update: function () {
  12052. },
  12053. /**
  12054. * Render is called right after the Game Renderer completes, but before the State.render.
  12055. * It is only called if visible is set to true.
  12056. * @method Phaser.Plugin#render
  12057. */
  12058. render: function () {
  12059. },
  12060. /**
  12061. * Post-render is called after the Game Renderer and State.render have run.
  12062. * It is only called if visible is set to true.
  12063. * @method Phaser.Plugin#postRender
  12064. */
  12065. postRender: function () {
  12066. },
  12067. /**
  12068. * Clear down this Plugin and null out references
  12069. * @method Phaser.Plugin#destroy
  12070. */
  12071. destroy: function () {
  12072. this.game = null;
  12073. this.parent = null;
  12074. this.active = false;
  12075. this.visible = false;
  12076. }
  12077. };
  12078. Phaser.Plugin.prototype.constructor = Phaser.Plugin;
  12079. /* jshint newcap: false */
  12080. /**
  12081. * @author Richard Davey <rich@photonstorm.com>
  12082. * @copyright 2014 Photon Storm Ltd.
  12083. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  12084. */
  12085. /**
  12086. * The Plugin Manager is responsible for the loading, running and unloading of Phaser Plugins.
  12087. *
  12088. * @class Phaser.PluginManager
  12089. * @classdesc Phaser - PluginManager
  12090. * @constructor
  12091. * @param {Phaser.Game} game - A reference to the currently running game.
  12092. */
  12093. Phaser.PluginManager = function(game) {
  12094. /**
  12095. * @property {Phaser.Game} game - A reference to the currently running game.
  12096. */
  12097. this.game = game;
  12098. /**
  12099. * @property {array} plugins - An array of all the plugins being managed by this PluginManager.
  12100. */
  12101. this.plugins = [];
  12102. /**
  12103. * @property {number} _len - Internal cache var.
  12104. * @private
  12105. */
  12106. this._len = 0;
  12107. /**
  12108. * @property {number} _i - Internal cache var.
  12109. * @private
  12110. */
  12111. this._i = 0;
  12112. };
  12113. Phaser.PluginManager.prototype = {
  12114. /**
  12115. * Add a new Plugin into the PluginManager.
  12116. * 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.
  12117. *
  12118. * @method Phaser.PluginManager#add
  12119. * @param {object|Phaser.Plugin} plugin - The Plugin to add into the PluginManager. This can be a function or an existing object.
  12120. * @return {Phaser.Plugin} The Plugin that was added to the manager.
  12121. */
  12122. add: function (plugin) {
  12123. var result = false;
  12124. // Prototype?
  12125. if (typeof plugin === 'function')
  12126. {
  12127. plugin = new plugin(this.game, this._parent);
  12128. }
  12129. else
  12130. {
  12131. plugin.game = this.game;
  12132. plugin.parent = this;
  12133. }
  12134. // Check for methods now to avoid having to do this every loop
  12135. if (typeof plugin['preUpdate'] === 'function')
  12136. {
  12137. plugin.hasPreUpdate = true;
  12138. result = true;
  12139. }
  12140. if (typeof plugin['update'] === 'function')
  12141. {
  12142. plugin.hasUpdate = true;
  12143. result = true;
  12144. }
  12145. if (typeof plugin['postUpdate'] === 'function')
  12146. {
  12147. plugin.hasPostUpdate = true;
  12148. result = true;
  12149. }
  12150. if (typeof plugin['render'] === 'function')
  12151. {
  12152. plugin.hasRender = true;
  12153. result = true;
  12154. }
  12155. if (typeof plugin['postRender'] === 'function')
  12156. {
  12157. plugin.hasPostRender = true;
  12158. result = true;
  12159. }
  12160. // The plugin must have at least one of the above functions to be added to the PluginManager.
  12161. if (result)
  12162. {
  12163. if (plugin.hasPreUpdate || plugin.hasUpdate || plugin.hasPostUpdate)
  12164. {
  12165. plugin.active = true;
  12166. }
  12167. if (plugin.hasRender || plugin.hasPostRender)
  12168. {
  12169. plugin.visible = true;
  12170. }
  12171. this._len = this.plugins.push(plugin);
  12172. // Allows plugins to run potentially destructive code outside of the constructor, and only if being added to the PluginManager
  12173. if (typeof plugin['init'] === 'function')
  12174. {
  12175. plugin.init();
  12176. }
  12177. return plugin;
  12178. }
  12179. else
  12180. {
  12181. return null;
  12182. }
  12183. },
  12184. /**
  12185. * Remove a Plugin from the PluginManager. It calls Plugin.destroy on the plugin before removing it from the manager.
  12186. *
  12187. * @method Phaser.PluginManager#remove
  12188. * @param {Phaser.Plugin} plugin - The plugin to be removed.
  12189. */
  12190. remove: function (plugin) {
  12191. this._i = this._len;
  12192. while (this._i--)
  12193. {
  12194. if (this.plugins[this._i] === plugin)
  12195. {
  12196. plugin.destroy();
  12197. this.plugins.splice(this._i, 1);
  12198. this._len--;
  12199. return;
  12200. }
  12201. }
  12202. },
  12203. /**
  12204. * Remove all Plugins from the PluginManager. It calls Plugin.destroy on every plugin before removing it from the manager.
  12205. *
  12206. * @method Phaser.PluginManager#removeAll
  12207. */
  12208. removeAll: function() {
  12209. this._i = this._len;
  12210. while (this._i--)
  12211. {
  12212. this.plugins[this._i].destroy();
  12213. }
  12214. this.plugins.length = 0;
  12215. this._len = 0;
  12216. },
  12217. /**
  12218. * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
  12219. * It only calls plugins who have active=true.
  12220. *
  12221. * @method Phaser.PluginManager#preUpdate
  12222. */
  12223. preUpdate: function () {
  12224. this._i = this._len;
  12225. while (this._i--)
  12226. {
  12227. if (this.plugins[this._i].active && this.plugins[this._i].hasPreUpdate)
  12228. {
  12229. this.plugins[this._i].preUpdate();
  12230. }
  12231. }
  12232. },
  12233. /**
  12234. * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
  12235. * It only calls plugins who have active=true.
  12236. *
  12237. * @method Phaser.PluginManager#update
  12238. */
  12239. update: function () {
  12240. this._i = this._len;
  12241. while (this._i--)
  12242. {
  12243. if (this.plugins[this._i].active && this.plugins[this._i].hasUpdate)
  12244. {
  12245. this.plugins[this._i].update();
  12246. }
  12247. }
  12248. },
  12249. /**
  12250. * PostUpdate is the last thing to be called before the world render.
  12251. * In particular, it is called after the world postUpdate, which means the camera has been adjusted.
  12252. * It only calls plugins who have active=true.
  12253. *
  12254. * @method Phaser.PluginManager#postUpdate
  12255. */
  12256. postUpdate: function () {
  12257. this._i = this._len;
  12258. while (this._i--)
  12259. {
  12260. if (this.plugins[this._i].active && this.plugins[this._i].hasPostUpdate)
  12261. {
  12262. this.plugins[this._i].postUpdate();
  12263. }
  12264. }
  12265. },
  12266. /**
  12267. * Render is called right after the Game Renderer completes, but before the State.render.
  12268. * It only calls plugins who have visible=true.
  12269. *
  12270. * @method Phaser.PluginManager#render
  12271. */
  12272. render: function () {
  12273. this._i = this._len;
  12274. while (this._i--)
  12275. {
  12276. if (this.plugins[this._i].visible && this.plugins[this._i].hasRender)
  12277. {
  12278. this.plugins[this._i].render();
  12279. }
  12280. }
  12281. },
  12282. /**
  12283. * Post-render is called after the Game Renderer and State.render have run.
  12284. * It only calls plugins who have visible=true.
  12285. *
  12286. * @method Phaser.PluginManager#postRender
  12287. */
  12288. postRender: function () {
  12289. this._i = this._len;
  12290. while (this._i--)
  12291. {
  12292. if (this.plugins[this._i].visible && this.plugins[this._i].hasPostRender)
  12293. {
  12294. this.plugins[this._i].postRender();
  12295. }
  12296. }
  12297. },
  12298. /**
  12299. * Clear down this PluginManager, calls destroy on every plugin and nulls out references.
  12300. *
  12301. * @method Phaser.PluginManager#destroy
  12302. */
  12303. destroy: function () {
  12304. this.removeAll();
  12305. this.game = null;
  12306. }
  12307. };
  12308. Phaser.PluginManager.prototype.constructor = Phaser.PluginManager;
  12309. /**
  12310. * @author Richard Davey <rich@photonstorm.com>
  12311. * @copyright 2014 Photon Storm Ltd.
  12312. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  12313. */
  12314. /**
  12315. * The Stage controls the canvas on which everything is displayed. It handles display within the browser,
  12316. * focus handling, game resizing, scaling and the pause, boot and orientation screens.
  12317. *
  12318. * @class Phaser.Stage
  12319. * @extends PIXI.Stage
  12320. * @constructor
  12321. * @param {Phaser.Game} game - Game reference to the currently running game.
  12322. * @param {number} width - Width of the canvas element.
  12323. * @param {number} height - Height of the canvas element.
  12324. */
  12325. Phaser.Stage = function (game, width, height) {
  12326. /**
  12327. * @property {Phaser.Game} game - A reference to the currently running Game.
  12328. */
  12329. this.game = game;
  12330. /**
  12331. * @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)
  12332. */
  12333. this.offset = new Phaser.Point();
  12334. PIXI.Stage.call(this, 0x000000, false);
  12335. /**
  12336. * @property {string} name - The name of this object.
  12337. * @default
  12338. */
  12339. this.name = '_stage_root';
  12340. this.interactive = false;
  12341. /**
  12342. * @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.
  12343. * @default
  12344. */
  12345. this.disableVisibilityChange = false;
  12346. /**
  12347. * @property {number|false} checkOffsetInterval - The time (in ms) between which the stage should check to see if it has moved.
  12348. * @default
  12349. */
  12350. this.checkOffsetInterval = 2500;
  12351. /**
  12352. * @property {boolean} exists - If exists is true the Stage and all children are updated, otherwise it is skipped.
  12353. * @default
  12354. */
  12355. this.exists = true;
  12356. /**
  12357. * @property {number} currentRenderOrderID - Reset each frame, keeps a count of the total number of objects updated.
  12358. */
  12359. this.currentRenderOrderID = 0;
  12360. /**
  12361. * @property {string} hiddenVar - The page visibility API event name.
  12362. * @private
  12363. */
  12364. this._hiddenVar = 'hidden';
  12365. /**
  12366. * @property {number} _nextOffsetCheck - The time to run the next offset check.
  12367. * @private
  12368. */
  12369. this._nextOffsetCheck = 0;
  12370. /**
  12371. * @property {number} _backgroundColor - Stage background color.
  12372. * @private
  12373. */
  12374. this._backgroundColor = 0x000000;
  12375. if (game.config)
  12376. {
  12377. this.parseConfig(game.config);
  12378. }
  12379. else
  12380. {
  12381. this.game.canvas = Phaser.Canvas.create(width, height);
  12382. this.game.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
  12383. }
  12384. };
  12385. Phaser.Stage.prototype = Object.create(PIXI.Stage.prototype);
  12386. Phaser.Stage.prototype.constructor = Phaser.Stage;
  12387. /**
  12388. * This is called automatically after the plugins preUpdate and before the State.update.
  12389. * Most objects have preUpdate methods and it's where initial movement and positioning is done.
  12390. *
  12391. * @method Phaser.Stage#preUpdate
  12392. */
  12393. Phaser.Stage.prototype.preUpdate = function () {
  12394. this.currentRenderOrderID = 0;
  12395. // This can't loop in reverse, we need the orderID to be in sequence
  12396. var len = this.children.length;
  12397. for (var i = 0; i < len; i++)
  12398. {
  12399. this.children[i].preUpdate();
  12400. }
  12401. };
  12402. /**
  12403. * This is called automatically after the State.update, but before particles or plugins update.
  12404. *
  12405. * @method Phaser.Stage#update
  12406. */
  12407. Phaser.Stage.prototype.update = function () {
  12408. var i = this.children.length;
  12409. while (i--)
  12410. {
  12411. this.children[i].update();
  12412. }
  12413. };
  12414. /**
  12415. * This is called automatically before the renderer runs and after the plugins have updated.
  12416. * In postUpdate this is where all the final physics calculatations and object positioning happens.
  12417. * The objects are processed in the order of the display list.
  12418. * The only exception to this is if the camera is following an object, in which case that is updated first.
  12419. *
  12420. * @method Phaser.Stage#postUpdate
  12421. */
  12422. Phaser.Stage.prototype.postUpdate = function () {
  12423. if (this.game.world.camera.target)
  12424. {
  12425. this.game.world.camera.target.postUpdate();
  12426. this.game.world.camera.update();
  12427. var i = this.children.length;
  12428. while (i--)
  12429. {
  12430. if (this.children[i] !== this.game.world.camera.target)
  12431. {
  12432. this.children[i].postUpdate();
  12433. }
  12434. }
  12435. }
  12436. else
  12437. {
  12438. this.game.world.camera.update();
  12439. var i = this.children.length;
  12440. while (i--)
  12441. {
  12442. this.children[i].postUpdate();
  12443. }
  12444. }
  12445. if (this.checkOffsetInterval !== false)
  12446. {
  12447. if (this.game.time.now > this._nextOffsetCheck)
  12448. {
  12449. Phaser.Canvas.getOffset(this.game.canvas, this.offset);
  12450. this._nextOffsetCheck = this.game.time.now + this.checkOffsetInterval;
  12451. }
  12452. }
  12453. };
  12454. /**
  12455. * Parses a Game configuration object.
  12456. *
  12457. * @method Phaser.Stage#parseConfig
  12458. * @protected
  12459. */
  12460. Phaser.Stage.prototype.parseConfig = function (config) {
  12461. if (config['canvasID'])
  12462. {
  12463. this.game.canvas = Phaser.Canvas.create(this.game.width, this.game.height, config['canvasID']);
  12464. }
  12465. else
  12466. {
  12467. this.game.canvas = Phaser.Canvas.create(this.game.width, this.game.height);
  12468. }
  12469. if (config['canvasStyle'])
  12470. {
  12471. this.game.canvas.stlye = config['canvasStyle'];
  12472. }
  12473. else
  12474. {
  12475. this.game.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
  12476. }
  12477. if (config['checkOffsetInterval'])
  12478. {
  12479. this.checkOffsetInterval = config['checkOffsetInterval'];
  12480. }
  12481. if (config['disableVisibilityChange'])
  12482. {
  12483. this.disableVisibilityChange = config['disableVisibilityChange'];
  12484. }
  12485. if (config['fullScreenScaleMode'])
  12486. {
  12487. this.fullScreenScaleMode = config['fullScreenScaleMode'];
  12488. }
  12489. if (config['scaleMode'])
  12490. {
  12491. this.scaleMode = config['scaleMode'];
  12492. }
  12493. if (config['backgroundColor'])
  12494. {
  12495. this.backgroundColor = config['backgroundColor'];
  12496. }
  12497. };
  12498. /**
  12499. * Initialises the stage and adds the event listeners.
  12500. * @method Phaser.Stage#boot
  12501. * @private
  12502. */
  12503. Phaser.Stage.prototype.boot = function () {
  12504. Phaser.Canvas.getOffset(this.game.canvas, this.offset);
  12505. this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, this.game.width, this.game.height);
  12506. var _this = this;
  12507. this._onChange = function (event) {
  12508. return _this.visibilityChange(event);
  12509. };
  12510. Phaser.Canvas.setUserSelect(this.game.canvas, 'none');
  12511. Phaser.Canvas.setTouchAction(this.game.canvas, 'none');
  12512. this.checkVisibility();
  12513. };
  12514. /**
  12515. * Starts a page visibility event listener running, or window.blur/focus if not supported by the browser.
  12516. * @method Phaser.Stage#checkVisibility
  12517. */
  12518. Phaser.Stage.prototype.checkVisibility = function () {
  12519. if (document.webkitHidden !== undefined)
  12520. {
  12521. this._hiddenVar = 'webkitvisibilitychange';
  12522. }
  12523. else if (document.mozHidden !== undefined)
  12524. {
  12525. this._hiddenVar = 'mozvisibilitychange';
  12526. }
  12527. else if (document.msHidden !== undefined)
  12528. {
  12529. this._hiddenVar = 'msvisibilitychange';
  12530. }
  12531. else if (document.hidden !== undefined)
  12532. {
  12533. this._hiddenVar = 'visibilitychange';
  12534. }
  12535. else
  12536. {
  12537. this._hiddenVar = null;
  12538. }
  12539. // Does browser support it? If not (like in IE9 or old Android) we need to fall back to blur/focus
  12540. if (this._hiddenVar)
  12541. {
  12542. document.addEventListener(this._hiddenVar, this._onChange, false);
  12543. }
  12544. window.onpagehide = this._onChange;
  12545. window.onpageshow = this._onChange;
  12546. window.onblur = this._onChange;
  12547. window.onfocus = this._onChange;
  12548. };
  12549. /**
  12550. * This method is called when the document visibility is changed.
  12551. * @method Phaser.Stage#visibilityChange
  12552. * @param {Event} event - Its type will be used to decide whether the game should be paused or not.
  12553. */
  12554. Phaser.Stage.prototype.visibilityChange = function (event) {
  12555. if (this.disableVisibilityChange)
  12556. {
  12557. return;
  12558. }
  12559. if (event.type === 'pagehide' || event.type === 'blur' || event.type === 'pageshow' || event.type === 'focus')
  12560. {
  12561. if (event.type === 'pagehide' || event.type === 'blur')
  12562. {
  12563. this.game.focusLoss(event);
  12564. }
  12565. else if (event.type === 'pageshow' || event.type === 'focus')
  12566. {
  12567. this.game.focusGain(event);
  12568. }
  12569. return;
  12570. }
  12571. if (document.hidden || document.mozHidden || document.msHidden || document.webkitHidden)
  12572. {
  12573. this.game.gamePaused(event);
  12574. }
  12575. else
  12576. {
  12577. this.game.gameResumed(event);
  12578. }
  12579. };
  12580. /**
  12581. * Sets the background color for the stage.
  12582. *
  12583. * @name Phaser.Stage#setBackgroundColor
  12584. * @param {number} backgroundColor - The color of the background, easiest way to pass this in is in hex format like: 0xFFFFFF for white.
  12585. */
  12586. Phaser.Stage.prototype.setBackgroundColor = function(backgroundColor)
  12587. {
  12588. this._backgroundColor = backgroundColor || 0x000000;
  12589. this.backgroundColorSplit = PIXI.hex2rgb(this.backgroundColor);
  12590. var hex = this._backgroundColor.toString(16);
  12591. hex = '000000'.substr(0, 6 - hex.length) + hex;
  12592. this.backgroundColorString = '#' + hex;
  12593. };
  12594. /**
  12595. * @name Phaser.Stage#backgroundColor
  12596. * @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'
  12597. */
  12598. Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", {
  12599. get: function () {
  12600. return this._backgroundColor;
  12601. },
  12602. set: function (color) {
  12603. this._backgroundColor = color;
  12604. if (this.game.transparent === false)
  12605. {
  12606. if (typeof color === 'string')
  12607. {
  12608. color = Phaser.Color.hexToRGB(color);
  12609. }
  12610. this.setBackgroundColor(color);
  12611. }
  12612. }
  12613. });
  12614. /**
  12615. * Enable or disable texture smoothing for all objects on this Stage. Only works for bitmap/image textures. Smoothing is enabled by default.
  12616. *
  12617. * @name Phaser.Stage#smoothed
  12618. * @property {boolean} smoothed - Set to true to smooth all sprites rendered on this Stage, or false to disable smoothing (great for pixel art)
  12619. */
  12620. Object.defineProperty(Phaser.Stage.prototype, "smoothed", {
  12621. get: function () {
  12622. return !PIXI.scaleModes.LINEAR;
  12623. },
  12624. set: function (value) {
  12625. if (value)
  12626. {
  12627. PIXI.scaleModes.LINEAR = 0;
  12628. }
  12629. else
  12630. {
  12631. PIXI.scaleModes.LINEAR = 1;
  12632. }
  12633. }
  12634. });
  12635. /**
  12636. * @author Richard Davey <rich@photonstorm.com>
  12637. * @copyright 2014 Photon Storm Ltd.
  12638. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  12639. */
  12640. /**
  12641. * Phaser Group constructor.
  12642. * @class Phaser.Group
  12643. * @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.
  12644. * @constructor
  12645. * @param {Phaser.Game} game - A reference to the currently running game.
  12646. * @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.
  12647. * @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging.
  12648. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  12649. * @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.
  12650. * @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.
  12651. */
  12652. Phaser.Group = function (game, parent, name, addToStage, enableBody, physicsBodyType) {
  12653. if (typeof addToStage === 'undefined') { addToStage = false; }
  12654. if (typeof enableBody === 'undefined') { enableBody = false; }
  12655. if (typeof physicsBodyType === 'undefined') { physicsBodyType = Phaser.Physics.ARCADE; }
  12656. /**
  12657. * @property {Phaser.Game} game - A reference to the currently running Game.
  12658. */
  12659. this.game = game;
  12660. if (typeof parent === 'undefined')
  12661. {
  12662. parent = game.world;
  12663. }
  12664. /**
  12665. * @property {string} name - A name for this Group. Not used internally but useful for debugging.
  12666. */
  12667. this.name = name || 'group';
  12668. PIXI.DisplayObjectContainer.call(this);
  12669. if (addToStage)
  12670. {
  12671. this.game.stage.addChild(this);
  12672. }
  12673. else
  12674. {
  12675. if (parent)
  12676. {
  12677. parent.addChild(this);
  12678. }
  12679. }
  12680. /**
  12681. * @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.
  12682. */
  12683. this.z = 0;
  12684. /**
  12685. * @property {number} type - Internal Phaser Type value.
  12686. * @protected
  12687. */
  12688. this.type = Phaser.GROUP;
  12689. /**
  12690. * @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.
  12691. * @default
  12692. */
  12693. this.alive = true;
  12694. /**
  12695. * @property {boolean} exists - If exists is true the Group is updated, otherwise it is skipped.
  12696. * @default
  12697. */
  12698. this.exists = true;
  12699. /**
  12700. * @property {Phaser.Group|Phaser.Sprite} parent - The parent of this Group.
  12701. */
  12702. /**
  12703. * @property {Phaser.Point} scale - The scale of the Group container.
  12704. */
  12705. this.scale = new Phaser.Point(1, 1);
  12706. /**
  12707. * @property {Phaser.Point} pivot - The pivot point of the Group container.
  12708. */
  12709. /**
  12710. * The cursor is a simple way to iterate through the objects in a Group using the Group.next and Group.previous functions.
  12711. * 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.
  12712. * @property {any} cursor - The current display object that the Group cursor is pointing to.
  12713. */
  12714. this.cursor = null;
  12715. /**
  12716. * @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.
  12717. */
  12718. this.cameraOffset = new Phaser.Point();
  12719. /**
  12720. * @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`.
  12721. * @default
  12722. */
  12723. this.enableBody = enableBody;
  12724. /**
  12725. * @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.
  12726. */
  12727. this.enableBodyDebug = false;
  12728. /**
  12729. * @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.
  12730. */
  12731. this.physicsBodyType = physicsBodyType;
  12732. /**
  12733. * @property {string} _sortProperty - The property on which children are sorted.
  12734. * @private
  12735. */
  12736. this._sortProperty = 'z';
  12737. /**
  12738. * A small internal cache:
  12739. * 0 = previous position.x
  12740. * 1 = previous position.y
  12741. * 2 = previous rotation
  12742. * 3 = renderID
  12743. * 4 = fresh? (0 = no, 1 = yes)
  12744. * 5 = outOfBoundsFired (0 = no, 1 = yes)
  12745. * 6 = exists (0 = no, 1 = yes)
  12746. * 7 = fixed to camera (0 = no, 1 = yes)
  12747. * 8 = cursor index
  12748. * 9 = sort order
  12749. * @property {Array} _cache
  12750. * @private
  12751. */
  12752. this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 ];
  12753. };
  12754. Phaser.Group.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  12755. Phaser.Group.prototype.constructor = Phaser.Group;
  12756. /**
  12757. * @constant
  12758. * @type {number}
  12759. */
  12760. Phaser.Group.RETURN_NONE = 0;
  12761. /**
  12762. * @constant
  12763. * @type {number}
  12764. */
  12765. Phaser.Group.RETURN_TOTAL = 1;
  12766. /**
  12767. * @constant
  12768. * @type {number}
  12769. */
  12770. Phaser.Group.RETURN_CHILD = 2;
  12771. /**
  12772. * @constant
  12773. * @type {number}
  12774. */
  12775. Phaser.Group.SORT_ASCENDING = -1;
  12776. /**
  12777. * @constant
  12778. * @type {number}
  12779. */
  12780. Phaser.Group.SORT_DESCENDING = 1;
  12781. /**
  12782. * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object.
  12783. * 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
  12784. * that then see the addAt method.
  12785. *
  12786. * @see Phaser.Group#create
  12787. * @see Phaser.Group#addAt
  12788. * @method Phaser.Group#add
  12789. * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object..
  12790. * @return {*} The child that was added to the Group.
  12791. */
  12792. Phaser.Group.prototype.add = function (child) {
  12793. if (child.parent !== this)
  12794. {
  12795. if (this.enableBody)
  12796. {
  12797. this.game.physics.enable(child, this.physicsBodyType);
  12798. }
  12799. this.addChild(child);
  12800. child.z = this.children.length;
  12801. if (child.events)
  12802. {
  12803. child.events.onAddedToGroup.dispatch(child, this);
  12804. }
  12805. if (this.cursor === null)
  12806. {
  12807. this.cursor = child;
  12808. }
  12809. }
  12810. return child;
  12811. };
  12812. /**
  12813. * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object.
  12814. * The child is added to the Group at the location specified by the index value, this allows you to control child ordering.
  12815. *
  12816. * @method Phaser.Group#addAt
  12817. * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object..
  12818. * @param {number} index - The index within the Group to insert the child to.
  12819. * @return {*} The child that was added to the Group.
  12820. */
  12821. Phaser.Group.prototype.addAt = function (child, index) {
  12822. if (child.parent !== this)
  12823. {
  12824. if (this.enableBody)
  12825. {
  12826. this.game.physics.enable(child, this.physicsBodyType);
  12827. }
  12828. this.addChildAt(child, index);
  12829. this.updateZ();
  12830. if (child.events)
  12831. {
  12832. child.events.onAddedToGroup.dispatch(child, this);
  12833. }
  12834. if (this.cursor === null)
  12835. {
  12836. this.cursor = child;
  12837. }
  12838. }
  12839. return child;
  12840. };
  12841. /**
  12842. * Returns the child found at the given index within this Group.
  12843. *
  12844. * @method Phaser.Group#getAt
  12845. * @param {number} index - The index to return the child from.
  12846. * @return {*} The child that was found at the given index. If the index was out of bounds then this will return -1.
  12847. */
  12848. Phaser.Group.prototype.getAt = function (index) {
  12849. if (index < 0 || index >= this.children.length)
  12850. {
  12851. return -1;
  12852. }
  12853. else
  12854. {
  12855. return this.getChildAt(index);
  12856. }
  12857. };
  12858. /**
  12859. * Automatically creates a new Phaser.Sprite object and adds it to the top of this Group.
  12860. * Useful if you don't need to create the Sprite instances before-hand.
  12861. *
  12862. * @method Phaser.Group#create
  12863. * @param {number} x - The x coordinate to display the newly created Sprite at. The value is in relation to the Group.x point.
  12864. * @param {number} y - The y coordinate to display the newly created Sprite at. The value is in relation to the Group.y point.
  12865. * @param {string} key - The Game.cache key of the image that this Sprite will use.
  12866. * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
  12867. * @param {boolean} [exists=true] - The default exists state of the Sprite.
  12868. * @return {Phaser.Sprite} The child that was created.
  12869. */
  12870. Phaser.Group.prototype.create = function (x, y, key, frame, exists) {
  12871. if (typeof exists === 'undefined') { exists = true; }
  12872. var child = new Phaser.Sprite(this.game, x, y, key, frame);
  12873. if (this.enableBody)
  12874. {
  12875. this.game.physics.enable(child, this.physicsBodyType);
  12876. }
  12877. child.exists = exists;
  12878. child.visible = exists;
  12879. child.alive = exists;
  12880. this.addChild(child);
  12881. child.z = this.children.length;
  12882. if (child.events)
  12883. {
  12884. child.events.onAddedToGroup.dispatch(child, this);
  12885. }
  12886. if (this.cursor === null)
  12887. {
  12888. this.cursor = child;
  12889. }
  12890. return child;
  12891. };
  12892. /**
  12893. * Automatically creates multiple Phaser.Sprite objects and adds them to the top of this Group.
  12894. * 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
  12895. * and will be positioned at 0, 0 (relative to the Group.x/y)
  12896. *
  12897. * @method Phaser.Group#createMultiple
  12898. * @param {number} quantity - The number of Sprites to create.
  12899. * @param {string} key - The Game.cache key of the image that this Sprite will use.
  12900. * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
  12901. * @param {boolean} [exists=false] - The default exists state of the Sprite.
  12902. */
  12903. Phaser.Group.prototype.createMultiple = function (quantity, key, frame, exists) {
  12904. if (typeof exists === 'undefined') { exists = false; }
  12905. for (var i = 0; i < quantity; i++)
  12906. {
  12907. this.create(0, 0, key, frame, exists);
  12908. }
  12909. };
  12910. /**
  12911. * Internal method that re-applies all of the childrens Z values.
  12912. *
  12913. * @method Phaser.Group#updateZ
  12914. * @protected
  12915. */
  12916. Phaser.Group.prototype.updateZ = function () {
  12917. var i = this.children.length;
  12918. while (i--)
  12919. {
  12920. this.children[i].z = i;
  12921. }
  12922. };
  12923. /**
  12924. * 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.
  12925. *
  12926. * @method Phaser.Group#next
  12927. * @return {*} The child the cursor now points to.
  12928. */
  12929. Phaser.Group.prototype.next = function () {
  12930. if (this.cursor)
  12931. {
  12932. // Wrap the cursor?
  12933. if (this._cache[8] >= this.children.length - 1)
  12934. {
  12935. this._cache[8] = 0;
  12936. }
  12937. else
  12938. {
  12939. this._cache[8]++;
  12940. }
  12941. this.cursor = this.children[this._cache[8]];
  12942. return this.cursor;
  12943. }
  12944. };
  12945. /**
  12946. * 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.
  12947. *
  12948. * @method Phaser.Group#previous
  12949. * @return {*} The child the cursor now points to.
  12950. */
  12951. Phaser.Group.prototype.previous = function () {
  12952. if (this.cursor)
  12953. {
  12954. // Wrap the cursor?
  12955. if (this._cache[8] === 0)
  12956. {
  12957. this._cache[8] = this.children.length - 1;
  12958. }
  12959. else
  12960. {
  12961. this._cache[8]--;
  12962. }
  12963. this.cursor = this.children[this._cache[8]];
  12964. return this.cursor;
  12965. }
  12966. };
  12967. /**
  12968. * Swaps the position of two children in this Group. Both children must be in this Group.
  12969. * You cannot swap a child with itself, or swap un-parented children, doing so will return false.
  12970. *
  12971. * @method Phaser.Group#swap
  12972. * @param {*} child1 - The first child to swap.
  12973. * @param {*} child2 - The second child to swap.
  12974. */
  12975. Phaser.Group.prototype.swap = function (child1, child2) {
  12976. var result = this.swapChildren(child1, child2);
  12977. if (result)
  12978. {
  12979. this.updateZ();
  12980. }
  12981. return result;
  12982. };
  12983. /**
  12984. * Brings the given child to the top of this Group so it renders above all other children.
  12985. *
  12986. * @method Phaser.Group#bringToTop
  12987. * @param {*} child - The child to bring to the top of this Group.
  12988. * @return {*} The child that was moved.
  12989. */
  12990. Phaser.Group.prototype.bringToTop = function (child) {
  12991. if (child.parent === this && this.getIndex(child) < this.children.length)
  12992. {
  12993. this.remove(child);
  12994. this.add(child);
  12995. }
  12996. return child;
  12997. };
  12998. /**
  12999. * Sends the given child to the bottom of this Group so it renders below all other children.
  13000. *
  13001. * @method Phaser.Group#sendToBack
  13002. * @param {*} child - The child to send to the bottom of this Group.
  13003. * @return {*} The child that was moved.
  13004. */
  13005. Phaser.Group.prototype.sendToBack = function (child) {
  13006. if (child.parent === this && this.getIndex(child) > 0)
  13007. {
  13008. this.remove(child);
  13009. this.addAt(child, 0);
  13010. }
  13011. return child;
  13012. };
  13013. /**
  13014. * Moves the given child up one place in this Group unless it's already at the top.
  13015. *
  13016. * @method Phaser.Group#moveUp
  13017. * @param {*} child - The child to move up in the Group.
  13018. * @return {*} The child that was moved.
  13019. */
  13020. Phaser.Group.prototype.moveUp = function (child) {
  13021. if (child.parent === this && this.getIndex(child) < this.children.length - 1)
  13022. {
  13023. var a = this.getIndex(child);
  13024. var b = this.getAt(a + 1);
  13025. if (b)
  13026. {
  13027. this.swap(child, b);
  13028. }
  13029. }
  13030. return child;
  13031. };
  13032. /**
  13033. * Moves the given child down one place in this Group unless it's already at the top.
  13034. *
  13035. * @method Phaser.Group#moveDown
  13036. * @param {*} child - The child to move down in the Group.
  13037. * @return {*} The child that was moved.
  13038. */
  13039. Phaser.Group.prototype.moveDown = function (child) {
  13040. if (child.parent === this && this.getIndex(child) > 0)
  13041. {
  13042. var a = this.getIndex(child);
  13043. var b = this.getAt(a - 1);
  13044. if (b)
  13045. {
  13046. this.swap(child, b);
  13047. }
  13048. }
  13049. return child;
  13050. };
  13051. /**
  13052. * Positions the child found at the given index within this Group to the given x and y coordinates.
  13053. *
  13054. * @method Phaser.Group#xy
  13055. * @param {number} index - The index of the child in the Group to set the position of.
  13056. * @param {number} x - The new x position of the child.
  13057. * @param {number} y - The new y position of the child.
  13058. */
  13059. Phaser.Group.prototype.xy = function (index, x, y) {
  13060. if (index < 0 || index > this.children.length)
  13061. {
  13062. return -1;
  13063. }
  13064. else
  13065. {
  13066. this.getChildAt(index).x = x;
  13067. this.getChildAt(index).y = y;
  13068. }
  13069. };
  13070. /**
  13071. * Reverses all children in this Group. Note that this does not propagate, only direct children are re-ordered.
  13072. *
  13073. * @method Phaser.Group#reverse
  13074. */
  13075. Phaser.Group.prototype.reverse = function () {
  13076. this.children.reverse();
  13077. this.updateZ();
  13078. };
  13079. /**
  13080. * Get the index position of the given child in this Group. This should always match the childs z property.
  13081. *
  13082. * @method Phaser.Group#getIndex
  13083. * @param {*} child - The child to get the index for.
  13084. * @return {number} The index of the child or -1 if it's not a member of this Group.
  13085. */
  13086. Phaser.Group.prototype.getIndex = function (child) {
  13087. return this.children.indexOf(child);
  13088. };
  13089. /**
  13090. * Replaces a child of this Group with the given newChild. The newChild cannot be a member of this Group.
  13091. *
  13092. * @method Phaser.Group#replace
  13093. * @param {*} oldChild - The child in this Group that will be replaced.
  13094. * @param {*} newChild - The child to be inserted into this Group.
  13095. * @return {*} Returns the oldChild that was replaced within this Group.
  13096. */
  13097. Phaser.Group.prototype.replace = function (oldChild, newChild) {
  13098. var index = this.getIndex(oldChild);
  13099. if (index !== -1)
  13100. {
  13101. if (newChild.parent !== undefined)
  13102. {
  13103. newChild.events.onRemovedFromGroup.dispatch(newChild, this);
  13104. newChild.parent.removeChild(newChild);
  13105. if (newChild.parent instanceof Phaser.Group)
  13106. {
  13107. newChild.parent.updateZ();
  13108. }
  13109. }
  13110. var temp = oldChild;
  13111. this.remove(temp);
  13112. this.addAt(newChild, index);
  13113. return temp;
  13114. }
  13115. };
  13116. /**
  13117. * Sets the given property to the given value on the child. The operation controls the assignment of the value.
  13118. *
  13119. * @method Phaser.Group#setProperty
  13120. * @param {*} child - The child to set the property value on.
  13121. * @param {array} key - An array of strings that make up the property that will be set.
  13122. * @param {*} value - The value that will be set.
  13123. * @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.
  13124. */
  13125. Phaser.Group.prototype.setProperty = function (child, key, value, operation) {
  13126. operation = operation || 0;
  13127. // As ugly as this approach looks, and although it's limited to a depth of only 4, it's extremely fast.
  13128. // Much faster than a for loop or object iteration. There are no checks, so if the key isn't valid then it'll fail
  13129. // but as you are likely to call this from inner loops that have to perform well, I'll take that trade off.
  13130. // 0 = Equals
  13131. // 1 = Add
  13132. // 2 = Subtract
  13133. // 3 = Multiply
  13134. // 4 = Divide
  13135. var len = key.length;
  13136. if (len == 1)
  13137. {
  13138. if (operation === 0) { child[key[0]] = value; }
  13139. else if (operation == 1) { child[key[0]] += value; }
  13140. else if (operation == 2) { child[key[0]] -= value; }
  13141. else if (operation == 3) { child[key[0]] *= value; }
  13142. else if (operation == 4) { child[key[0]] /= value; }
  13143. }
  13144. else if (len == 2)
  13145. {
  13146. if (operation === 0) { child[key[0]][key[1]] = value; }
  13147. else if (operation == 1) { child[key[0]][key[1]] += value; }
  13148. else if (operation == 2) { child[key[0]][key[1]] -= value; }
  13149. else if (operation == 3) { child[key[0]][key[1]] *= value; }
  13150. else if (operation == 4) { child[key[0]][key[1]] /= value; }
  13151. }
  13152. else if (len == 3)
  13153. {
  13154. if (operation === 0) { child[key[0]][key[1]][key[2]] = value; }
  13155. else if (operation == 1) { child[key[0]][key[1]][key[2]] += value; }
  13156. else if (operation == 2) { child[key[0]][key[1]][key[2]] -= value; }
  13157. else if (operation == 3) { child[key[0]][key[1]][key[2]] *= value; }
  13158. else if (operation == 4) { child[key[0]][key[1]][key[2]] /= value; }
  13159. }
  13160. else if (len == 4)
  13161. {
  13162. if (operation === 0) { child[key[0]][key[1]][key[2]][key[3]] = value; }
  13163. else if (operation == 1) { child[key[0]][key[1]][key[2]][key[3]] += value; }
  13164. else if (operation == 2) { child[key[0]][key[1]][key[2]][key[3]] -= value; }
  13165. else if (operation == 3) { child[key[0]][key[1]][key[2]][key[3]] *= value; }
  13166. else if (operation == 4) { child[key[0]][key[1]][key[2]][key[3]] /= value; }
  13167. }
  13168. };
  13169. /**
  13170. * This function allows you to quickly set a property on a single child of this Group to a new value.
  13171. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  13172. *
  13173. * @method Phaser.Group#set
  13174. * @param {Phaser.Sprite} child - The child to set the property on.
  13175. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  13176. * @param {*} value - The value that will be set.
  13177. * @param {boolean} [checkAlive=false] - If set then the child will only be updated if alive=true.
  13178. * @param {boolean} [checkVisible=false] - If set then the child will only be updated if visible=true.
  13179. * @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.
  13180. */
  13181. Phaser.Group.prototype.set = function (child, key, value, checkAlive, checkVisible, operation) {
  13182. key = key.split('.');
  13183. if (typeof checkAlive === 'undefined') { checkAlive = false; }
  13184. if (typeof checkVisible === 'undefined') { checkVisible = false; }
  13185. if ((checkAlive === false || (checkAlive && child.alive)) && (checkVisible === false || (checkVisible && child.visible)))
  13186. {
  13187. this.setProperty(child, key, value, operation);
  13188. }
  13189. };
  13190. /**
  13191. * This function allows you to quickly set the same property across all children of this Group to a new value.
  13192. * 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.
  13193. * If you need that ability please see `Group.setAllChildren`.
  13194. *
  13195. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  13196. *
  13197. * @method Phaser.Group#setAll
  13198. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  13199. * @param {*} value - The value that will be set.
  13200. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
  13201. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
  13202. * @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.
  13203. */
  13204. Phaser.Group.prototype.setAll = function (key, value, checkAlive, checkVisible, operation) {
  13205. key = key.split('.');
  13206. if (typeof checkAlive === 'undefined') { checkAlive = false; }
  13207. if (typeof checkVisible === 'undefined') { checkVisible = false; }
  13208. operation = operation || 0;
  13209. for (var i = 0, len = this.children.length; i < len; i++)
  13210. {
  13211. if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
  13212. {
  13213. this.setProperty(this.children[i], key, value, operation);
  13214. }
  13215. }
  13216. };
  13217. /**
  13218. * This function allows you to quickly set the same property across all children of this Group, and any child Groups, to a new value.
  13219. *
  13220. * If this Group contains other Groups then the same property is set across their children as well, iterating down until it reaches the bottom.
  13221. * Unlike with Group.setAll the property is NOT set on child Groups itself.
  13222. *
  13223. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  13224. *
  13225. * @method Phaser.Group#setAllChildren
  13226. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  13227. * @param {*} value - The value that will be set.
  13228. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
  13229. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
  13230. * @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.
  13231. */
  13232. Phaser.Group.prototype.setAllChildren = function (key, value, checkAlive, checkVisible, operation) {
  13233. if (typeof checkAlive === 'undefined') { checkAlive = false; }
  13234. if (typeof checkVisible === 'undefined') { checkVisible = false; }
  13235. operation = operation || 0;
  13236. for (var i = 0, len = this.children.length; i < len; i++)
  13237. {
  13238. if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
  13239. {
  13240. if (this.children[i] instanceof Phaser.Group)
  13241. {
  13242. this.children[i].setAllChildren(key, value, checkAlive, checkVisible, operation);
  13243. }
  13244. else
  13245. {
  13246. this.setProperty(this.children[i], key.split('.'), value, operation);
  13247. }
  13248. }
  13249. }
  13250. };
  13251. /**
  13252. * Adds the amount to the given property on all children in this Group.
  13253. * Group.addAll('x', 10) will add 10 to the child.x value.
  13254. *
  13255. * @method Phaser.Group#addAll
  13256. * @param {string} property - The property to increment, for example 'body.velocity.x' or 'angle'.
  13257. * @param {number} amount - The amount to increment the property by. If child.x = 10 then addAll('x', 40) would make child.x = 50.
  13258. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  13259. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  13260. */
  13261. Phaser.Group.prototype.addAll = function (property, amount, checkAlive, checkVisible) {
  13262. this.setAll(property, amount, checkAlive, checkVisible, 1);
  13263. };
  13264. /**
  13265. * Subtracts the amount from the given property on all children in this Group.
  13266. * Group.subAll('x', 10) will minus 10 from the child.x value.
  13267. *
  13268. * @method Phaser.Group#subAll
  13269. * @param {string} property - The property to decrement, for example 'body.velocity.x' or 'angle'.
  13270. * @param {number} amount - The amount to subtract from the property. If child.x = 50 then subAll('x', 40) would make child.x = 10.
  13271. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  13272. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  13273. */
  13274. Phaser.Group.prototype.subAll = function (property, amount, checkAlive, checkVisible) {
  13275. this.setAll(property, amount, checkAlive, checkVisible, 2);
  13276. };
  13277. /**
  13278. * Multiplies the given property by the amount on all children in this Group.
  13279. * Group.multiplyAll('x', 2) will x2 the child.x value.
  13280. *
  13281. * @method Phaser.Group#multiplyAll
  13282. * @param {string} property - The property to multiply, for example 'body.velocity.x' or 'angle'.
  13283. * @param {number} amount - The amount to multiply the property by. If child.x = 10 then multiplyAll('x', 2) would make child.x = 20.
  13284. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  13285. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  13286. */
  13287. Phaser.Group.prototype.multiplyAll = function (property, amount, checkAlive, checkVisible) {
  13288. this.setAll(property, amount, checkAlive, checkVisible, 3);
  13289. };
  13290. /**
  13291. * Divides the given property by the amount on all children in this Group.
  13292. * Group.divideAll('x', 2) will half the child.x value.
  13293. *
  13294. * @method Phaser.Group#divideAll
  13295. * @param {string} property - The property to divide, for example 'body.velocity.x' or 'angle'.
  13296. * @param {number} amount - The amount to divide the property by. If child.x = 100 then divideAll('x', 2) would make child.x = 50.
  13297. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  13298. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  13299. */
  13300. Phaser.Group.prototype.divideAll = function (property, amount, checkAlive, checkVisible) {
  13301. this.setAll(property, amount, checkAlive, checkVisible, 4);
  13302. };
  13303. /**
  13304. * Calls a function on all of the children that have exists=true in this Group.
  13305. * After the existsValue parameter you can add as many parameters as you like, which will all be passed to the child callback.
  13306. *
  13307. * @method Phaser.Group#callAllExists
  13308. * @param {function} callback - The function that exists on the children that will be called.
  13309. * @param {boolean} existsValue - Only children with exists=existsValue will be called.
  13310. * @param {...*} parameter - Additional parameters that will be passed to the callback.
  13311. */
  13312. Phaser.Group.prototype.callAllExists = function (callback, existsValue) {
  13313. var args = Array.prototype.splice.call(arguments, 2);
  13314. for (var i = 0, len = this.children.length; i < len; i++)
  13315. {
  13316. if (this.children[i].exists === existsValue && this.children[i][callback])
  13317. {
  13318. this.children[i][callback].apply(this.children[i], args);
  13319. }
  13320. }
  13321. };
  13322. /**
  13323. * Returns a reference to a function that exists on a child of the Group based on the given callback array.
  13324. *
  13325. * @method Phaser.Group#callbackFromArray
  13326. * @param {object} child - The object to inspect.
  13327. * @param {array} callback - The array of function names.
  13328. * @param {number} length - The size of the array (pre-calculated in callAll).
  13329. * @protected
  13330. */
  13331. Phaser.Group.prototype.callbackFromArray = function (child, callback, length) {
  13332. // Kinda looks like a Christmas tree
  13333. if (length == 1)
  13334. {
  13335. if (child[callback[0]])
  13336. {
  13337. return child[callback[0]];
  13338. }
  13339. }
  13340. else if (length == 2)
  13341. {
  13342. if (child[callback[0]][callback[1]])
  13343. {
  13344. return child[callback[0]][callback[1]];
  13345. }
  13346. }
  13347. else if (length == 3)
  13348. {
  13349. if (child[callback[0]][callback[1]][callback[2]])
  13350. {
  13351. return child[callback[0]][callback[1]][callback[2]];
  13352. }
  13353. }
  13354. else if (length == 4)
  13355. {
  13356. if (child[callback[0]][callback[1]][callback[2]][callback[3]])
  13357. {
  13358. return child[callback[0]][callback[1]][callback[2]][callback[3]];
  13359. }
  13360. }
  13361. else
  13362. {
  13363. if (child[callback])
  13364. {
  13365. return child[callback];
  13366. }
  13367. }
  13368. return false;
  13369. };
  13370. /**
  13371. * Calls a function on all of the children regardless if they are dead or alive (see callAllExists if you need control over that)
  13372. * After the method parameter and context you can add as many extra parameters as you like, which will all be passed to the child.
  13373. *
  13374. * @method Phaser.Group#callAll
  13375. * @param {string} method - A string containing the name of the function that will be called. The function must exist on the child.
  13376. * @param {string} [context=null] - A string containing the context under which the method will be executed. Set to null to default to the child.
  13377. * @param {...*} parameter - Additional parameters that will be passed to the method.
  13378. */
  13379. Phaser.Group.prototype.callAll = function (method, context) {
  13380. if (typeof method === 'undefined')
  13381. {
  13382. return;
  13383. }
  13384. // Extract the method into an array
  13385. method = method.split('.');
  13386. var methodLength = method.length;
  13387. if (typeof context === 'undefined' || context === null || context === '')
  13388. {
  13389. context = null;
  13390. }
  13391. else
  13392. {
  13393. // Extract the context into an array
  13394. if (typeof context === 'string')
  13395. {
  13396. context = context.split('.');
  13397. var contextLength = context.length;
  13398. }
  13399. }
  13400. var args = Array.prototype.splice.call(arguments, 2);
  13401. var callback = null;
  13402. var callbackContext = null;
  13403. for (var i = 0, len = this.children.length; i < len; i++)
  13404. {
  13405. callback = this.callbackFromArray(this.children[i], method, methodLength);
  13406. if (context && callback)
  13407. {
  13408. callbackContext = this.callbackFromArray(this.children[i], context, contextLength);
  13409. if (callback)
  13410. {
  13411. callback.apply(callbackContext, args);
  13412. }
  13413. }
  13414. else if (callback)
  13415. {
  13416. callback.apply(this.children[i], args);
  13417. }
  13418. }
  13419. };
  13420. /**
  13421. * The core preUpdate - as called by World.
  13422. * @method Phaser.Group#preUpdate
  13423. * @protected
  13424. */
  13425. Phaser.Group.prototype.preUpdate = function () {
  13426. if (!this.exists || !this.parent.exists)
  13427. {
  13428. this.renderOrderID = -1;
  13429. return false;
  13430. }
  13431. var i = this.children.length;
  13432. while (i--)
  13433. {
  13434. this.children[i].preUpdate();
  13435. }
  13436. return true;
  13437. };
  13438. /**
  13439. * The core update - as called by World.
  13440. * @method Phaser.Group#update
  13441. * @protected
  13442. */
  13443. Phaser.Group.prototype.update = function () {
  13444. var i = this.children.length;
  13445. while (i--)
  13446. {
  13447. this.children[i].update();
  13448. }
  13449. };
  13450. /**
  13451. * The core postUpdate - as called by World.
  13452. * @method Phaser.Group#postUpdate
  13453. * @protected
  13454. */
  13455. Phaser.Group.prototype.postUpdate = function () {
  13456. // Fixed to Camera?
  13457. if (this._cache[7] === 1)
  13458. {
  13459. this.x = this.game.camera.view.x + this.cameraOffset.x;
  13460. this.y = this.game.camera.view.y + this.cameraOffset.y;
  13461. }
  13462. var i = this.children.length;
  13463. while (i--)
  13464. {
  13465. this.children[i].postUpdate();
  13466. }
  13467. };
  13468. /**
  13469. * 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.
  13470. * 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.
  13471. * For example: Group.forEach(awardBonusGold, this, true, 100, 500)
  13472. * Note: Currently this will skip any children which are Groups themselves.
  13473. *
  13474. * @method Phaser.Group#forEach
  13475. * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
  13476. * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
  13477. * @param {boolean} [checkExists=false] - If set only children with exists=true will be passed to the callback, otherwise all children will be passed.
  13478. */
  13479. Phaser.Group.prototype.forEach = function (callback, callbackContext, checkExists) {
  13480. if (typeof checkExists === 'undefined') { checkExists = false; }
  13481. var args = Array.prototype.splice.call(arguments, 3);
  13482. args.unshift(null);
  13483. for (var i = 0, len = this.children.length; i < len; i++)
  13484. {
  13485. if (!checkExists || (checkExists && this.children[i].exists))
  13486. {
  13487. args[0] = this.children[i];
  13488. callback.apply(callbackContext, args);
  13489. }
  13490. }
  13491. };
  13492. /**
  13493. * 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.
  13494. * You can add as many parameters as you like, which will all be passed to the callback along with the child.
  13495. * For example: Group.forEachExists(causeDamage, this, 500)
  13496. *
  13497. * @method Phaser.Group#forEachExists
  13498. * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
  13499. * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
  13500. */
  13501. Phaser.Group.prototype.forEachExists = function (callback, callbackContext) {
  13502. var args = Array.prototype.splice.call(arguments, 2);
  13503. args.unshift(null);
  13504. this.iterate('exists', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  13505. };
  13506. /**
  13507. * 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.
  13508. * You can add as many parameters as you like, which will all be passed to the callback along with the child.
  13509. * For example: Group.forEachAlive(causeDamage, this, 500)
  13510. *
  13511. * @method Phaser.Group#forEachAlive
  13512. * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
  13513. * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
  13514. */
  13515. Phaser.Group.prototype.forEachAlive = function (callback, callbackContext) {
  13516. var args = Array.prototype.splice.call(arguments, 2);
  13517. args.unshift(null);
  13518. this.iterate('alive', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  13519. };
  13520. /**
  13521. * 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.
  13522. * You can add as many parameters as you like, which will all be passed to the callback along with the child.
  13523. * For example: Group.forEachDead(bringToLife, this)
  13524. *
  13525. * @method Phaser.Group#forEachDead
  13526. * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter.
  13527. * @param {Object} callbackContext - The context in which the function should be called (usually 'this').
  13528. */
  13529. Phaser.Group.prototype.forEachDead = function (callback, callbackContext) {
  13530. var args = Array.prototype.splice.call(arguments, 2);
  13531. args.unshift(null);
  13532. this.iterate('alive', false, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  13533. };
  13534. /**
  13535. * Call this function to sort the group according to a particular value and order.
  13536. * 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()`.
  13537. *
  13538. * @method Phaser.Group#sort
  13539. * @param {string} [index='z'] - The `string` name of the property you want to sort on. Defaults to the objects z-depth value.
  13540. * @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.
  13541. */
  13542. Phaser.Group.prototype.sort = function (index, order) {
  13543. if (this.children.length < 2)
  13544. {
  13545. // Nothing to swap
  13546. return;
  13547. }
  13548. if (typeof index === 'undefined') { index = 'z'; }
  13549. if (typeof order === 'undefined') { order = Phaser.Group.SORT_ASCENDING; }
  13550. this._sortProperty = index;
  13551. if (order === Phaser.Group.SORT_ASCENDING)
  13552. {
  13553. this.children.sort(this.ascendingSortHandler.bind(this));
  13554. }
  13555. else
  13556. {
  13557. this.children.sort(this.descendingSortHandler.bind(this));
  13558. }
  13559. this.updateZ();
  13560. };
  13561. /**
  13562. * This allows you to use your own sort handler function.
  13563. * 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.
  13564. *
  13565. * @method Phaser.Group#customSort
  13566. * @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.
  13567. * @param {object} context - The scope in which the sortHandler is called.
  13568. */
  13569. Phaser.Group.prototype.customSort = function (sortHandler, context) {
  13570. if (this.children.length < 2)
  13571. {
  13572. // Nothing to swap
  13573. return;
  13574. }
  13575. this.children.sort(sortHandler.bind(context));
  13576. this.updateZ();
  13577. };
  13578. /**
  13579. * An internal helper function for the sort process.
  13580. *
  13581. * @method Phaser.Group#ascendingSortHandler
  13582. * @param {object} a - The first object being sorted.
  13583. * @param {object} b - The second object being sorted.
  13584. */
  13585. Phaser.Group.prototype.ascendingSortHandler = function (a, b) {
  13586. if (a[this._sortProperty] < b[this._sortProperty])
  13587. {
  13588. return -1;
  13589. }
  13590. else if (a[this._sortProperty] > b[this._sortProperty])
  13591. {
  13592. return 1;
  13593. }
  13594. else
  13595. {
  13596. if (a.z < b.z)
  13597. {
  13598. return -1;
  13599. }
  13600. else
  13601. {
  13602. return 1;
  13603. }
  13604. }
  13605. };
  13606. /**
  13607. * An internal helper function for the sort process.
  13608. *
  13609. * @method Phaser.Group#descendingSortHandler
  13610. * @param {object} a - The first object being sorted.
  13611. * @param {object} b - The second object being sorted.
  13612. */
  13613. Phaser.Group.prototype.descendingSortHandler = function (a, b) {
  13614. if (a[this._sortProperty] < b[this._sortProperty])
  13615. {
  13616. return 1;
  13617. }
  13618. else if (a[this._sortProperty] > b[this._sortProperty])
  13619. {
  13620. return -1;
  13621. }
  13622. else
  13623. {
  13624. return 0;
  13625. }
  13626. };
  13627. /**
  13628. * 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.
  13629. * Matched children can be sent to the optional callback, or simply returned or counted.
  13630. * 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.
  13631. *
  13632. * @method Phaser.Group#iterate
  13633. * @param {string} key - The child property to check, i.e. 'exists', 'alive', 'health'
  13634. * @param {any} value - If child.key === this value it will be considered a match. Note that a strict comparison is used.
  13635. * @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.
  13636. * @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.
  13637. * @param {Object} [callbackContext] - The context in which the function should be called (usually 'this').
  13638. * @return {any} Returns either a numeric total (if RETURN_TOTAL was specified) or the child object.
  13639. */
  13640. Phaser.Group.prototype.iterate = function (key, value, returnType, callback, callbackContext, args) {
  13641. if (returnType === Phaser.Group.RETURN_TOTAL && this.children.length === 0)
  13642. {
  13643. return 0;
  13644. }
  13645. if (typeof callback === 'undefined')
  13646. {
  13647. callback = false;
  13648. }
  13649. var total = 0;
  13650. for (var i = 0, len = this.children.length; i < len; i++)
  13651. {
  13652. if (this.children[i][key] === value)
  13653. {
  13654. total++;
  13655. if (callback)
  13656. {
  13657. args[0] = this.children[i];
  13658. callback.apply(callbackContext, args);
  13659. }
  13660. if (returnType === Phaser.Group.RETURN_CHILD)
  13661. {
  13662. return this.children[i];
  13663. }
  13664. }
  13665. }
  13666. if (returnType === Phaser.Group.RETURN_TOTAL)
  13667. {
  13668. return total;
  13669. }
  13670. else if (returnType === Phaser.Group.RETURN_CHILD)
  13671. {
  13672. return null;
  13673. }
  13674. };
  13675. /**
  13676. * Call this function to retrieve the first object with exists == (the given state) in the Group.
  13677. *
  13678. * @method Phaser.Group#getFirstExists
  13679. * @param {boolean} state - True or false.
  13680. * @return {Any} The first child, or null if none found.
  13681. */
  13682. Phaser.Group.prototype.getFirstExists = function (state) {
  13683. if (typeof state !== 'boolean')
  13684. {
  13685. state = true;
  13686. }
  13687. return this.iterate('exists', state, Phaser.Group.RETURN_CHILD);
  13688. };
  13689. /**
  13690. * Call this function to retrieve the first object with alive === true in the group.
  13691. * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc.
  13692. *
  13693. * @method Phaser.Group#getFirstAlive
  13694. * @return {Any} The first alive child, or null if none found.
  13695. */
  13696. Phaser.Group.prototype.getFirstAlive = function () {
  13697. return this.iterate('alive', true, Phaser.Group.RETURN_CHILD);
  13698. };
  13699. /**
  13700. * Call this function to retrieve the first object with alive === false in the group.
  13701. * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc.
  13702. *
  13703. * @method Phaser.Group#getFirstDead
  13704. * @return {Any} The first dead child, or null if none found.
  13705. */
  13706. Phaser.Group.prototype.getFirstDead = function () {
  13707. return this.iterate('alive', false, Phaser.Group.RETURN_CHILD);
  13708. };
  13709. /**
  13710. * Returns the child at the top of this Group. The top is the one being displayed (rendered) above every other child.
  13711. *
  13712. * @method Phaser.Group#getTop
  13713. * @return {Any} The child at the top of the Group.
  13714. */
  13715. Phaser.Group.prototype.getTop = function () {
  13716. if (this.children.length > 0)
  13717. {
  13718. return this.children[this.children.length - 1];
  13719. }
  13720. };
  13721. /**
  13722. * Returns the child at the bottom of this Group. The bottom is the one being displayed (rendered) below every other child.
  13723. *
  13724. * @method Phaser.Group#getBottom
  13725. * @return {Any} The child at the bottom of the Group.
  13726. */
  13727. Phaser.Group.prototype.getBottom = function () {
  13728. if (this.children.length > 0)
  13729. {
  13730. return this.children[0];
  13731. }
  13732. };
  13733. /**
  13734. * Call this function to find out how many members of the group are alive.
  13735. *
  13736. * @method Phaser.Group#countLiving
  13737. * @return {number} The number of children flagged as alive.
  13738. */
  13739. Phaser.Group.prototype.countLiving = function () {
  13740. return this.iterate('alive', true, Phaser.Group.RETURN_TOTAL);
  13741. };
  13742. /**
  13743. * Call this function to find out how many members of the group are dead.
  13744. *
  13745. * @method Phaser.Group#countDead
  13746. * @return {number} The number of children flagged as dead.
  13747. */
  13748. Phaser.Group.prototype.countDead = function () {
  13749. return this.iterate('alive', false, Phaser.Group.RETURN_TOTAL);
  13750. };
  13751. /**
  13752. * Returns a member at random from the group.
  13753. *
  13754. * @method Phaser.Group#getRandom
  13755. * @param {number} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array.
  13756. * @param {number} length - Optional restriction on the number of values you want to randomly select from.
  13757. * @return {Any} A random child of this Group.
  13758. */
  13759. Phaser.Group.prototype.getRandom = function (startIndex, length) {
  13760. if (this.children.length === 0)
  13761. {
  13762. return null;
  13763. }
  13764. startIndex = startIndex || 0;
  13765. length = length || this.children.length;
  13766. return this.game.math.getRandom(this.children, startIndex, length);
  13767. };
  13768. /**
  13769. * Removes the given child from this Group and sets its group property to null.
  13770. *
  13771. * @method Phaser.Group#remove
  13772. * @param {Any} child - The child to remove.
  13773. * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
  13774. * @return {boolean} true if the child was removed from this Group, otherwise false.
  13775. */
  13776. Phaser.Group.prototype.remove = function (child, destroy) {
  13777. if (typeof destroy === 'undefined') { destroy = false; }
  13778. if (this.children.length === 0)
  13779. {
  13780. return false;
  13781. }
  13782. if (child.events)
  13783. {
  13784. child.events.onRemovedFromGroup.dispatch(child, this);
  13785. }
  13786. this.removeChild(child);
  13787. this.updateZ();
  13788. if (this.cursor === child)
  13789. {
  13790. this.next();
  13791. }
  13792. if (destroy)
  13793. {
  13794. child.destroy();
  13795. }
  13796. return true;
  13797. };
  13798. /**
  13799. * Removes all children from this Group, setting all group properties to null.
  13800. * The Group container remains on the display list.
  13801. *
  13802. * @method Phaser.Group#removeAll
  13803. * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
  13804. */
  13805. Phaser.Group.prototype.removeAll = function (destroy) {
  13806. if (typeof destroy === 'undefined') { destroy = false; }
  13807. if (this.children.length === 0)
  13808. {
  13809. return;
  13810. }
  13811. do
  13812. {
  13813. if (this.children[0].events)
  13814. {
  13815. this.children[0].events.onRemovedFromGroup.dispatch(this.children[0], this);
  13816. }
  13817. this.removeChild(this.children[0]);
  13818. if (destroy)
  13819. {
  13820. this.children[0].destroy();
  13821. }
  13822. }
  13823. while (this.children.length > 0);
  13824. this.cursor = null;
  13825. };
  13826. /**
  13827. * Removes all children from this Group whos index falls beteen the given startIndex and endIndex values.
  13828. *
  13829. * @method Phaser.Group#removeBetween
  13830. * @param {number} startIndex - The index to start removing children from.
  13831. * @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.
  13832. * @param {boolean} [destroy=false] - You can optionally call destroy on the child that was removed.
  13833. */
  13834. Phaser.Group.prototype.removeBetween = function (startIndex, endIndex, destroy) {
  13835. if (typeof endIndex === 'undefined') { endIndex = this.children.length; }
  13836. if (typeof destroy === 'undefined') { destroy = false; }
  13837. if (this.children.length === 0)
  13838. {
  13839. return;
  13840. }
  13841. if (startIndex > endIndex || startIndex < 0 || endIndex > this.children.length)
  13842. {
  13843. return false;
  13844. }
  13845. var i = endIndex;
  13846. while (i >= startIndex)
  13847. {
  13848. if (this.children[i].events)
  13849. {
  13850. this.children[i].events.onRemovedFromGroup.dispatch(this.children[i], this);
  13851. }
  13852. this.removeChild(this.children[i]);
  13853. if (destroy)
  13854. {
  13855. this.children[i].destroy();
  13856. }
  13857. if (this.cursor === this.children[i])
  13858. {
  13859. this.cursor = null;
  13860. }
  13861. i--;
  13862. }
  13863. this.updateZ();
  13864. };
  13865. /**
  13866. * Destroys this Group. Removes all children, then removes the container from the display list and nulls references.
  13867. *
  13868. * @method Phaser.Group#destroy
  13869. * @param {boolean} [destroyChildren=true] - Should every child of this Group have its destroy method called?
  13870. * @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.
  13871. */
  13872. Phaser.Group.prototype.destroy = function (destroyChildren, soft) {
  13873. if (this.game === null) { return; }
  13874. if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
  13875. if (typeof soft === 'undefined') { soft = false; }
  13876. if (destroyChildren)
  13877. {
  13878. if (this.children.length > 0)
  13879. {
  13880. do
  13881. {
  13882. if (this.children[0].parent)
  13883. {
  13884. this.children[0].destroy(destroyChildren);
  13885. }
  13886. }
  13887. while (this.children.length > 0);
  13888. }
  13889. }
  13890. else
  13891. {
  13892. this.removeAll();
  13893. }
  13894. this.cursor = null;
  13895. if (!soft)
  13896. {
  13897. this.parent.removeChild(this);
  13898. this.game = null;
  13899. this.exists = false;
  13900. }
  13901. };
  13902. /**
  13903. * @name Phaser.Group#total
  13904. * @property {number} total - The total number of children in this Group who have a state of exists = true.
  13905. * @readonly
  13906. */
  13907. Object.defineProperty(Phaser.Group.prototype, "total", {
  13908. get: function () {
  13909. return this.iterate('exists', true, Phaser.Group.RETURN_TOTAL);
  13910. }
  13911. });
  13912. /**
  13913. * @name Phaser.Group#length
  13914. * @property {number} length - The total number of children in this Group, regardless of their exists/alive status.
  13915. * @readonly
  13916. */
  13917. Object.defineProperty(Phaser.Group.prototype, "length", {
  13918. get: function () {
  13919. return this.children.length;
  13920. }
  13921. });
  13922. /**
  13923. * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation.
  13924. * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position.
  13925. * @name Phaser.Group#angle
  13926. * @property {number} angle - The angle of rotation given in degrees, where 0 degrees = to the right.
  13927. */
  13928. Object.defineProperty(Phaser.Group.prototype, "angle", {
  13929. get: function() {
  13930. return Phaser.Math.radToDeg(this.rotation);
  13931. },
  13932. set: function(value) {
  13933. this.rotation = Phaser.Math.degToRad(value);
  13934. }
  13935. });
  13936. /**
  13937. * 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.
  13938. * Note that the cameraOffset values are in addition to any parent in the display list.
  13939. * So if this Group was in a Group that has x: 200, then this will be added to the cameraOffset.x
  13940. *
  13941. * @name Phaser.Group#fixedToCamera
  13942. * @property {boolean} fixedToCamera - Set to true to fix this Group to the Camera at its current world coordinates.
  13943. */
  13944. Object.defineProperty(Phaser.Group.prototype, "fixedToCamera", {
  13945. get: function () {
  13946. return !!this._cache[7];
  13947. },
  13948. set: function (value) {
  13949. if (value)
  13950. {
  13951. this._cache[7] = 1;
  13952. this.cameraOffset.set(this.x, this.y);
  13953. }
  13954. else
  13955. {
  13956. this._cache[7] = 0;
  13957. }
  13958. }
  13959. });
  13960. // Documentation stubs
  13961. /**
  13962. * The x coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates.
  13963. * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
  13964. * @name Phaser.Group#x
  13965. * @property {number} x - The x coordinate of the Group container.
  13966. */
  13967. /**
  13968. * The y coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates.
  13969. * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
  13970. * @name Phaser.Group#y
  13971. * @property {number} y - The y coordinate of the Group container.
  13972. */
  13973. /**
  13974. * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation.
  13975. * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position.
  13976. * @name Phaser.Group#rotation
  13977. * @property {number} rotation - The angle of rotation given in radians.
  13978. */
  13979. /**
  13980. * @name Phaser.Group#visible
  13981. * @property {boolean} visible - The visible state of the Group. Non-visible Groups and all of their children are not rendered.
  13982. */
  13983. /**
  13984. * @name Phaser.Group#alpha
  13985. * @property {number} alpha - The alpha value of the Group container.
  13986. */
  13987. /**
  13988. * @author Richard Davey <rich@photonstorm.com>
  13989. * @copyright 2014 Photon Storm Ltd.
  13990. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13991. */
  13992. /**
  13993. * "This world is but a canvas to our imagination." - Henry David Thoreau
  13994. *
  13995. * A game has only one world. The world is an abstract place in which all game objects live. It is not bound
  13996. * by stage limits and can be any size. You look into the world via cameras. All game objects live within
  13997. * the world at world-based coordinates. By default a world is created the same size as your Stage.
  13998. *
  13999. * @class Phaser.World
  14000. * @extends Phaser.Group
  14001. * @constructor
  14002. * @param {Phaser.Game} game - Reference to the current game instance.
  14003. */
  14004. Phaser.World = function (game) {
  14005. Phaser.Group.call(this, game, null, '__world', false);
  14006. /**
  14007. * 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.
  14008. * 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.
  14009. * 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.
  14010. * 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.
  14011. * @property {Phaser.Rectangle} bounds - Bound of this world that objects can not escape from.
  14012. */
  14013. this.bounds = new Phaser.Rectangle(0, 0, game.width, game.height);
  14014. /**
  14015. * @property {Phaser.Camera} camera - Camera instance.
  14016. */
  14017. this.camera = null;
  14018. };
  14019. Phaser.World.prototype = Object.create(Phaser.Group.prototype);
  14020. Phaser.World.prototype.constructor = Phaser.World;
  14021. /**
  14022. * Initialises the game world.
  14023. *
  14024. * @method Phaser.World#boot
  14025. * @protected
  14026. */
  14027. Phaser.World.prototype.boot = function () {
  14028. this.camera = new Phaser.Camera(this.game, 0, 0, 0, this.game.width, this.game.height);
  14029. this.camera.displayObject = this;
  14030. this.camera.scale = this.scale;
  14031. this.game.camera = this.camera;
  14032. this.game.stage.addChild(this);
  14033. };
  14034. /**
  14035. * Updates the size of this world. Note that this doesn't modify the world x/y coordinates, just the width and height.
  14036. *
  14037. * @method Phaser.World#setBounds
  14038. * @param {number} x - Top left most corner of the world.
  14039. * @param {number} y - Top left most corner of the world.
  14040. * @param {number} width - New width of the world. Can never be smaller than the Game.width.
  14041. * @param {number} height - New height of the world. Can never be smaller than the Game.height.
  14042. */
  14043. Phaser.World.prototype.setBounds = function (x, y, width, height) {
  14044. if (width < this.game.width)
  14045. {
  14046. width = this.game.width;
  14047. }
  14048. if (height < this.game.height)
  14049. {
  14050. height = this.game.height;
  14051. }
  14052. this.bounds.setTo(x, y, width, height);
  14053. if (this.camera.bounds)
  14054. {
  14055. // The Camera can never be smaller than the game size
  14056. this.camera.bounds.setTo(x, y, width, height);
  14057. }
  14058. this.game.physics.setBoundsToWorld();
  14059. };
  14060. /**
  14061. * Destroyer of worlds.
  14062. *
  14063. * @method Phaser.World#shutdown
  14064. */
  14065. Phaser.World.prototype.shutdown = function () {
  14066. // World is a Group, so run a soft destruction on this and all children.
  14067. this.destroy(true, true);
  14068. };
  14069. /**
  14070. * @name Phaser.World#width
  14071. * @property {number} width - Gets or sets the current width of the game world.
  14072. */
  14073. Object.defineProperty(Phaser.World.prototype, "width", {
  14074. get: function () {
  14075. return this.bounds.width;
  14076. },
  14077. set: function (value) {
  14078. this.bounds.width = value;
  14079. }
  14080. });
  14081. /**
  14082. * @name Phaser.World#height
  14083. * @property {number} height - Gets or sets the current height of the game world.
  14084. */
  14085. Object.defineProperty(Phaser.World.prototype, "height", {
  14086. get: function () {
  14087. return this.bounds.height;
  14088. },
  14089. set: function (value) {
  14090. this.bounds.height = value;
  14091. }
  14092. });
  14093. /**
  14094. * @name Phaser.World#centerX
  14095. * @property {number} centerX - Gets the X position corresponding to the center point of the world.
  14096. * @readonly
  14097. */
  14098. Object.defineProperty(Phaser.World.prototype, "centerX", {
  14099. get: function () {
  14100. return this.bounds.halfWidth;
  14101. }
  14102. });
  14103. /**
  14104. * @name Phaser.World#centerY
  14105. * @property {number} centerY - Gets the Y position corresponding to the center point of the world.
  14106. * @readonly
  14107. */
  14108. Object.defineProperty(Phaser.World.prototype, "centerY", {
  14109. get: function () {
  14110. return this.bounds.halfHeight;
  14111. }
  14112. });
  14113. /**
  14114. * @name Phaser.World#randomX
  14115. * @property {number} randomX - Gets a random integer which is lesser than or equal to the current width of the game world.
  14116. * @readonly
  14117. */
  14118. Object.defineProperty(Phaser.World.prototype, "randomX", {
  14119. get: function () {
  14120. if (this.bounds.x < 0)
  14121. {
  14122. return this.game.rnd.integerInRange(this.bounds.x, (this.bounds.width - Math.abs(this.bounds.x)));
  14123. }
  14124. else
  14125. {
  14126. return this.game.rnd.integerInRange(this.bounds.x, this.bounds.width);
  14127. }
  14128. }
  14129. });
  14130. /**
  14131. * @name Phaser.World#randomY
  14132. * @property {number} randomY - Gets a random integer which is lesser than or equal to the current height of the game world.
  14133. * @readonly
  14134. */
  14135. Object.defineProperty(Phaser.World.prototype, "randomY", {
  14136. get: function () {
  14137. if (this.bounds.y < 0)
  14138. {
  14139. return this.game.rnd.integerInRange(this.bounds.y, (this.bounds.height - Math.abs(this.bounds.y)));
  14140. }
  14141. else
  14142. {
  14143. return this.game.rnd.integerInRange(this.bounds.y, this.bounds.height);
  14144. }
  14145. }
  14146. });
  14147. /**
  14148. * @author Richard Davey <rich@photonstorm.com>
  14149. * @copyright 2014 Photon Storm Ltd.
  14150. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  14151. */
  14152. /**
  14153. * The ScaleManager object is responsible for helping you manage the scaling, resizing and alignment of your game within the browser.
  14154. *
  14155. * @class Phaser.ScaleManager
  14156. * @constructor
  14157. * @param {Phaser.Game} game - A reference to the currently running game.
  14158. * @param {number} width - The native width of the game.
  14159. * @param {number} height - The native height of the game.
  14160. */
  14161. Phaser.ScaleManager = function (game, width, height) {
  14162. /**
  14163. * @property {Phaser.Game} game - A reference to the currently running game.
  14164. */
  14165. this.game = game;
  14166. /**
  14167. * @property {number} width - Width of the stage after calculation.
  14168. */
  14169. this.width = width;
  14170. /**
  14171. * @property {number} height - Height of the stage after calculation.
  14172. */
  14173. this.height = height;
  14174. /**
  14175. * @property {number} minWidth - Minimum width the canvas should be scaled to (in pixels).
  14176. */
  14177. this.minWidth = null;
  14178. /**
  14179. * @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.
  14180. */
  14181. this.maxWidth = null;
  14182. /**
  14183. * @property {number} minHeight - Minimum height the canvas should be scaled to (in pixels).
  14184. */
  14185. this.minHeight = null;
  14186. /**
  14187. * @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.
  14188. */
  14189. this.maxHeight = null;
  14190. /**
  14191. * @property {boolean} forceLandscape - If the game should be forced to use Landscape mode, this is set to true by Game.Stage
  14192. * @default
  14193. */
  14194. this.forceLandscape = false;
  14195. /**
  14196. * @property {boolean} forcePortrait - If the game should be forced to use Portrait mode, this is set to true by Game.Stage
  14197. * @default
  14198. */
  14199. this.forcePortrait = false;
  14200. /**
  14201. * @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.
  14202. * @default
  14203. */
  14204. this.incorrectOrientation = false;
  14205. /**
  14206. * @property {boolean} pageAlignHorizontally - If you wish to align your game in the middle of the page then you can set this value to true.
  14207. * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing.
  14208. * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
  14209. * @default
  14210. */
  14211. this.pageAlignHorizontally = false;
  14212. /**
  14213. * @property {boolean} pageAlignVertically - If you wish to align your game in the middle of the page then you can set this value to true.
  14214. * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing.
  14215. * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
  14216. * @default
  14217. */
  14218. this.pageAlignVertically = false;
  14219. /**
  14220. * @property {number} maxIterations - The maximum number of times it will try to resize the canvas to fill the browser.
  14221. * @default
  14222. */
  14223. this.maxIterations = 5;
  14224. /**
  14225. * @property {PIXI.Sprite} orientationSprite - The Sprite that is optionally displayed if the browser enters an unsupported orientation.
  14226. */
  14227. this.orientationSprite = null;
  14228. /**
  14229. * @property {Phaser.Signal} enterLandscape - The event that is dispatched when the browser enters landscape orientation.
  14230. */
  14231. this.enterLandscape = new Phaser.Signal();
  14232. /**
  14233. * @property {Phaser.Signal} enterPortrait - The event that is dispatched when the browser enters horizontal orientation.
  14234. */
  14235. this.enterPortrait = new Phaser.Signal();
  14236. /**
  14237. * @property {Phaser.Signal} enterIncorrectOrientation - The event that is dispatched when the browser enters an incorrect orientation, as defined by forceOrientation.
  14238. */
  14239. this.enterIncorrectOrientation = new Phaser.Signal();
  14240. /**
  14241. * @property {Phaser.Signal} leaveIncorrectOrientation - The event that is dispatched when the browser leaves an incorrect orientation, as defined by forceOrientation.
  14242. */
  14243. this.leaveIncorrectOrientation = new Phaser.Signal();
  14244. /**
  14245. * @property {Phaser.Signal} hasResized - The event that is dispatched when the game scale changes.
  14246. */
  14247. this.hasResized = new Phaser.Signal();
  14248. /**
  14249. * 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.
  14250. * 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.
  14251. * Note that if you use a scale property of EXACT_FIT then fullScreenTarget will have its width and height style set to 100%.
  14252. * @property {any} fullScreenTarget
  14253. */
  14254. this.fullScreenTarget = this.game.canvas;
  14255. /**
  14256. * @property {Phaser.Signal} enterFullScreen - The event that is dispatched when the browser enters full screen mode (if it supports the FullScreen API).
  14257. */
  14258. this.enterFullScreen = new Phaser.Signal();
  14259. /**
  14260. * @property {Phaser.Signal} leaveFullScreen - The event that is dispatched when the browser leaves full screen mode (if it supports the FullScreen API).
  14261. */
  14262. this.leaveFullScreen = new Phaser.Signal();
  14263. /**
  14264. * @property {number} orientation - The orientation value of the game (as defined by window.orientation if set). 90 = landscape. 0 = portrait.
  14265. */
  14266. this.orienta