diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/src/pixi/textures/BaseTexture.js b/src/pixi/textures/BaseTexture.js index 5f954e2..ed2705f 100644 --- a/src/pixi/textures/BaseTexture.js +++ b/src/pixi/textures/BaseTexture.js @@ -3,8 +3,6 @@ */ PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; PIXI.BaseTextureCacheIdGenerator = 0; @@ -87,9 +85,10 @@ // used for webGL this._glTextures = []; - // used for webGL texture updating... - this._dirty = []; + // TODO - this needs to be addressed + this._dirty = [true, true, true, true]; + if(!source)return; @@ -98,8 +97,7 @@ this.hasLoaded = true; this.width = this.source.naturalWidth || this.source.width; this.height = this.source.naturalHeight || this.source.height; - - PIXI.texturesToUpdate.push(this); + this.dirty(); } else { @@ -111,10 +109,7 @@ scope.width = scope.source.naturalWidth || scope.source.width; scope.height = scope.source.naturalHeight || scope.source.height; - for (var i = 0; i < scope._glTextures.length; i++) - { - scope._dirty[i] = true; - } + scope.dirty(); // add it to somewhere... scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -153,7 +148,20 @@ delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; - PIXI.texturesToDestroy.push(this); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; }; /** @@ -169,6 +177,14 @@ this.source.src = newSrc; }; +PIXI.BaseTexture.prototype.dirty = function() +{ + for (var i = 0; i < this._glTextures.length; i++) + { + this._dirty[i] = true; + } +}; + /** * Helper function that returns a base texture based on an image url * If the image is not in the base texture cache it will be created and loaded diff --git a/Gruntfile.js b/Gruntfile.js index 761deb1..43b963d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,12 @@ var srcFiles = [ '<%= dirs.src %>/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/src/pixi/textures/BaseTexture.js b/src/pixi/textures/BaseTexture.js index 5f954e2..ed2705f 100644 --- a/src/pixi/textures/BaseTexture.js +++ b/src/pixi/textures/BaseTexture.js @@ -3,8 +3,6 @@ */ PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; PIXI.BaseTextureCacheIdGenerator = 0; @@ -87,9 +85,10 @@ // used for webGL this._glTextures = []; - // used for webGL texture updating... - this._dirty = []; + // TODO - this needs to be addressed + this._dirty = [true, true, true, true]; + if(!source)return; @@ -98,8 +97,7 @@ this.hasLoaded = true; this.width = this.source.naturalWidth || this.source.width; this.height = this.source.naturalHeight || this.source.height; - - PIXI.texturesToUpdate.push(this); + this.dirty(); } else { @@ -111,10 +109,7 @@ scope.width = scope.source.naturalWidth || scope.source.width; scope.height = scope.source.naturalHeight || scope.source.height; - for (var i = 0; i < scope._glTextures.length; i++) - { - scope._dirty[i] = true; - } + scope.dirty(); // add it to somewhere... scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -153,7 +148,20 @@ delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; - PIXI.texturesToDestroy.push(this); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; }; /** @@ -169,6 +177,14 @@ this.source.src = newSrc; }; +PIXI.BaseTexture.prototype.dirty = function() +{ + for (var i = 0; i < this._glTextures.length; i++) + { + this._dirty[i] = true; + } +}; + /** * Helper function that returns a base texture based on an image url * If the image is not in the base texture cache it will be created and loaded diff --git a/src/pixi/textures/RenderTexture.js b/src/pixi/textures/RenderTexture.js index edb86cf..b5c4577 100644 --- a/src/pixi/textures/RenderTexture.js +++ b/src/pixi/textures/RenderTexture.js @@ -118,9 +118,8 @@ } this.valid = true; - PIXI.Texture.frameUpdates.push(this); - + this._updateUvs(); }; PIXI.RenderTexture.prototype = Object.create(PIXI.Texture.prototype); @@ -136,10 +135,7 @@ */ PIXI.RenderTexture.prototype.resize = function(width, height, updateBase) { - if (width === this.width && height === this.height) - { - return; - } + if (width === this.width && height === this.height)return; this.valid = (width > 0 && height > 0); @@ -189,13 +185,31 @@ * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn * @private */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, matrix, clear) { if(!this.valid)return; //TOOD replace position with matrix.. - var gl = this.renderer.gl; + + //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix + var wt = displayObject.worldTransform; + wt.identity(); + wt.translate(0, this.projection.y * 2); + if(matrix)wt.append(matrix); + wt.scale(1,-1); - gl.colorMask(true, true, true, true); + // setWorld Alpha to ensure that the object is renderer at full opacity + displayObject.worldAlpha = 1; + + // Time to update all the children of the displayObject with the new matrix.. + var children = displayObject.children; + + for(var i=0,j=children.length; i/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/src/pixi/textures/BaseTexture.js b/src/pixi/textures/BaseTexture.js index 5f954e2..ed2705f 100644 --- a/src/pixi/textures/BaseTexture.js +++ b/src/pixi/textures/BaseTexture.js @@ -3,8 +3,6 @@ */ PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; PIXI.BaseTextureCacheIdGenerator = 0; @@ -87,9 +85,10 @@ // used for webGL this._glTextures = []; - // used for webGL texture updating... - this._dirty = []; + // TODO - this needs to be addressed + this._dirty = [true, true, true, true]; + if(!source)return; @@ -98,8 +97,7 @@ this.hasLoaded = true; this.width = this.source.naturalWidth || this.source.width; this.height = this.source.naturalHeight || this.source.height; - - PIXI.texturesToUpdate.push(this); + this.dirty(); } else { @@ -111,10 +109,7 @@ scope.width = scope.source.naturalWidth || scope.source.width; scope.height = scope.source.naturalHeight || scope.source.height; - for (var i = 0; i < scope._glTextures.length; i++) - { - scope._dirty[i] = true; - } + scope.dirty(); // add it to somewhere... scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -153,7 +148,20 @@ delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; - PIXI.texturesToDestroy.push(this); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; }; /** @@ -169,6 +177,14 @@ this.source.src = newSrc; }; +PIXI.BaseTexture.prototype.dirty = function() +{ + for (var i = 0; i < this._glTextures.length; i++) + { + this._dirty[i] = true; + } +}; + /** * Helper function that returns a base texture based on an image url * If the image is not in the base texture cache it will be created and loaded diff --git a/src/pixi/textures/RenderTexture.js b/src/pixi/textures/RenderTexture.js index edb86cf..b5c4577 100644 --- a/src/pixi/textures/RenderTexture.js +++ b/src/pixi/textures/RenderTexture.js @@ -118,9 +118,8 @@ } this.valid = true; - PIXI.Texture.frameUpdates.push(this); - + this._updateUvs(); }; PIXI.RenderTexture.prototype = Object.create(PIXI.Texture.prototype); @@ -136,10 +135,7 @@ */ PIXI.RenderTexture.prototype.resize = function(width, height, updateBase) { - if (width === this.width && height === this.height) - { - return; - } + if (width === this.width && height === this.height)return; this.valid = (width > 0 && height > 0); @@ -189,13 +185,31 @@ * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn * @private */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, matrix, clear) { if(!this.valid)return; //TOOD replace position with matrix.. - var gl = this.renderer.gl; + + //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix + var wt = displayObject.worldTransform; + wt.identity(); + wt.translate(0, this.projection.y * 2); + if(matrix)wt.append(matrix); + wt.scale(1,-1); - gl.colorMask(true, true, true, true); + // setWorld Alpha to ensure that the object is renderer at full opacity + displayObject.worldAlpha = 1; + + // Time to update all the children of the displayObject with the new matrix.. + var children = displayObject.children; + + for(var i=0,j=children.length; i/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/src/pixi/textures/BaseTexture.js b/src/pixi/textures/BaseTexture.js index 5f954e2..ed2705f 100644 --- a/src/pixi/textures/BaseTexture.js +++ b/src/pixi/textures/BaseTexture.js @@ -3,8 +3,6 @@ */ PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; PIXI.BaseTextureCacheIdGenerator = 0; @@ -87,9 +85,10 @@ // used for webGL this._glTextures = []; - // used for webGL texture updating... - this._dirty = []; + // TODO - this needs to be addressed + this._dirty = [true, true, true, true]; + if(!source)return; @@ -98,8 +97,7 @@ this.hasLoaded = true; this.width = this.source.naturalWidth || this.source.width; this.height = this.source.naturalHeight || this.source.height; - - PIXI.texturesToUpdate.push(this); + this.dirty(); } else { @@ -111,10 +109,7 @@ scope.width = scope.source.naturalWidth || scope.source.width; scope.height = scope.source.naturalHeight || scope.source.height; - for (var i = 0; i < scope._glTextures.length; i++) - { - scope._dirty[i] = true; - } + scope.dirty(); // add it to somewhere... scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -153,7 +148,20 @@ delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; - PIXI.texturesToDestroy.push(this); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; }; /** @@ -169,6 +177,14 @@ this.source.src = newSrc; }; +PIXI.BaseTexture.prototype.dirty = function() +{ + for (var i = 0; i < this._glTextures.length; i++) + { + this._dirty[i] = true; + } +}; + /** * Helper function that returns a base texture based on an image url * If the image is not in the base texture cache it will be created and loaded diff --git a/src/pixi/textures/RenderTexture.js b/src/pixi/textures/RenderTexture.js index edb86cf..b5c4577 100644 --- a/src/pixi/textures/RenderTexture.js +++ b/src/pixi/textures/RenderTexture.js @@ -118,9 +118,8 @@ } this.valid = true; - PIXI.Texture.frameUpdates.push(this); - + this._updateUvs(); }; PIXI.RenderTexture.prototype = Object.create(PIXI.Texture.prototype); @@ -136,10 +135,7 @@ */ PIXI.RenderTexture.prototype.resize = function(width, height, updateBase) { - if (width === this.width && height === this.height) - { - return; - } + if (width === this.width && height === this.height)return; this.valid = (width > 0 && height > 0); @@ -189,13 +185,31 @@ * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn * @private */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, matrix, clear) { if(!this.valid)return; //TOOD replace position with matrix.. - var gl = this.renderer.gl; + + //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix + var wt = displayObject.worldTransform; + wt.identity(); + wt.translate(0, this.projection.y * 2); + if(matrix)wt.append(matrix); + wt.scale(1,-1); - gl.colorMask(true, true, true, true); + // setWorld Alpha to ensure that the object is renderer at full opacity + displayObject.worldAlpha = 1; + + // Time to update all the children of the displayObject with the new matrix.. + var children = displayObject.children; + + for(var i=0,j=children.length; i/Intro.js', '<%= dirs.src %>/Pixi.js', - '<%= dirs.src %>/core/Point.js', - '<%= dirs.src %>/core/Rectangle.js', - '<%= dirs.src %>/core/Polygon.js', - '<%= dirs.src %>/core/Circle.js', - '<%= dirs.src %>/core/Ellipse.js', - '<%= dirs.src %>/core/Matrix.js', + '<%= dirs.src %>/geom/Point.js', + '<%= dirs.src %>/geom/Rectangle.js', + '<%= dirs.src %>/geom/Polygon.js', + '<%= dirs.src %>/geom/Circle.js', + '<%= dirs.src %>/geom/Ellipse.js', + '<%= dirs.src %>/geom/Matrix.js', '<%= dirs.src %>/display/DisplayObject.js', '<%= dirs.src %>/display/DisplayObjectContainer.js', '<%= dirs.src %>/display/Sprite.js', diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js index bf596cc..abcf3fd 100644 --- a/src/pixi/InteractionManager.js +++ b/src/pixi/InteractionManager.js @@ -531,8 +531,7 @@ // temp fix for if the element is in a non visible - var isSprite = (item instanceof PIXI.Sprite), - worldTransform = item.worldTransform, + var worldTransform = item.worldTransform, i, a00 = worldTransform.a, a01 = worldTransform.b, a02 = worldTransform.tx, a10 = worldTransform.c, a11 = worldTransform.d, a12 = worldTransform.ty, id = 1 / (a00 * a11 + a01 * -a10), @@ -553,7 +552,7 @@ return false; } // a sprite with no hitarea defined - else if(isSprite) + else if(item instanceof PIXI.Sprite) { var width = item.texture.frame.width, height = item.texture.frame.height, @@ -572,10 +571,29 @@ } } } + else if(item instanceof PIXI.Graphics) + { + var graphicsData = item.graphicsData; + for (i = 0; i < graphicsData.length; i++) + { + var data = graphicsData[i]; + if(!data.fill)continue; + + // only deal with fills.. + if(data.shape) + { + if(data.shape.contains(x, y)) + { + interactionData.target = item; + return true; + } + } + } + } var length = item.children.length; - for (var i = 0; i < length; i++) + for (i = 0; i < length; i++) { var tempItem = item.children[i]; var hit = this.hitTest(tempItem, interactionData); diff --git a/src/pixi/Pixi.js b/src/pixi/Pixi.js index 3872d0d..1eb1010 100644 --- a/src/pixi/Pixi.js +++ b/src/pixi/Pixi.js @@ -16,7 +16,7 @@ PIXI.CANVAS_RENDERER = 1; // useful for testing against if your lib is using pixi. -PIXI.VERSION = "v1.6.1"; +PIXI.VERSION = "v2.0.0"; // the various blend modes supported by pixi @@ -65,6 +65,7 @@ PIXI.INTERACTION_FREQUENCY = 30; PIXI.AUTO_PREVENT_DEFAULT = true; +PIXI.PI_2 = Math.PI * 2; PIXI.RAD_TO_DEG = 180 / Math.PI; PIXI.DEG_TO_RAD = Math.PI / 180; diff --git a/src/pixi/core/Circle.js b/src/pixi/core/Circle.js deleted file mode 100644 index cc39a28..0000000 --- a/src/pixi/core/Circle.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class Circle - * @constructor - * @param x {Number} The X coordinate of the center of this circle - * @param y {Number} The Y coordinate of the center of this circle - * @param radius {Number} The radius of the circle - */ -PIXI.Circle = function(x, y, radius) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property radius - * @type Number - * @default 0 - */ - this.radius = radius || 0; -}; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the polygon - */ -PIXI.Circle.prototype.clone = function() -{ - return new PIXI.Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x, and y coordinates passed to this function are contained within this circle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coordinates are within this polygon - */ -PIXI.Circle.prototype.contains = function(x, y) -{ - if(this.radius <= 0) - return false; - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Circle.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -// constructor -PIXI.Circle.prototype.constructor = PIXI.Circle; - diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js deleted file mode 100644 index b376333..0000000 --- a/src/pixi/core/Ellipse.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Chad Engler - */ - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class Ellipse - * @constructor - * @param x {Number} The X coordinate of the center of the ellipse - * @param y {Number} The Y coordinate of the center of the ellipse - * @param width {Number} The half width of this ellipse - * @param height {Number} The half height of this ellipse - */ -PIXI.Ellipse = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -PIXI.Ellipse.prototype.clone = function() -{ - return new PIXI.Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this ellipse - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this ellipse - */ -PIXI.Ellipse.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -PIXI.Ellipse.prototype.getBounds = function() -{ - return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -// constructor -PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/core/Matrix.js b/src/pixi/core/Matrix.js deleted file mode 100644 index 16f74fe..0000000 --- a/src/pixi/core/Matrix.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class Matrix - * @constructor - */ -PIXI.Matrix = function() -{ - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; -}; - -/** - * Creates a pixi matrix object based on the array given as a parameter - * - * @method fromArray - * @param array {Array} The array that the matrix will be filled with - */ -PIXI.Matrix.prototype.fromArray = function(array) -{ - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object - * - * @method toArray - * @param transpose {Boolean} Whether we need to transpose the matrix or not - * @return {Array} the newly created array which contains the matrix - */ -PIXI.Matrix.prototype.toArray = function(transpose) -{ - if(!this.array) this.array = new PIXI.Float32Array(9); - var array = this.array; - - if(transpose) - { - array[0] = this.a; - array[1] = this.c; - array[2] = 0; - array[3] = this.b; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else - { - array[0] = this.a; - array[1] = this.b; - array[2] = this.tx; - array[3] = this.c; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transormation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed trough this matrix - */ -PIXI.Matrix.prototype.apply = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - newPos.x = this.a * pos.x + this.b * pos.y + this.tx; - newPos.y = this.c * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transormation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @method apply - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed trough this matrix - */ -PIXI.Matrix.prototype.applyInverse = function(pos, newPos) -{ - newPos = newPos || new PIXI.Point(); - - var id = 1 / (this.a * this.d + this.b * -this.c); - newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.translate = function(x, y) -{ - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally - * @param {Number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.scale = function(x, y) -{ - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - **/ -PIXI.Matrix.prototype.rotate = function(angle) -{ - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - - - - - -PIXI.identityMatrix = new PIXI.Matrix(); - -PIXI.determineMatrixArrayType = function() { - return (typeof Float32Array !== 'undefined') ? Float32Array : Array; -}; - -/** - * The Matrix2 class will choose the best type of array to use between - * a regular javascript Array and a Float32Array if the latter is available - * - * @class Matrix2 - * @constructor - */ -PIXI.Matrix2 = PIXI.determineMatrixArrayType(); diff --git a/src/pixi/core/Point.js b/src/pixi/core/Point.js deleted file mode 100644 index 202bc2f..0000000 --- a/src/pixi/core/Point.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ - -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. - * - * @class Point - * @constructor - * @param x {Number} position of the point on the x axis - * @param y {Number} position of the point on the y axis - */ -PIXI.Point = function(x, y) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; -}; - -/** - * Creates a clone of this point - * - * @method clone - * @return {Point} a copy of the point - */ -PIXI.Point.prototype.clone = function() -{ - return new PIXI.Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is ommited, both x and y will be set to x. - * - * @method set - * @param [x=0] {Number} position of the point on the x axis - * @param [y=0] {Number} position of the point on the y axis - */ -PIXI.Point.prototype.set = function(x, y) -{ - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -// constructor -PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/core/Polygon.js b/src/pixi/core/Polygon.js deleted file mode 100644 index b118818..0000000 --- a/src/pixi/core/Polygon.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @author Adrien Brault - */ - -/** - * @class Polygon - * @constructor - * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -PIXI.Polygon = function(points) -{ - //if points isn't an array, use arguments as the array - if(!(points instanceof Array)) - points = Array.prototype.slice.call(arguments); - - //if this is a flat array of numbers, convert it to points - if(typeof points[0] === 'number') { - var p = []; - for(var i = 0, il = points.length; i < il; i+=2) { - p.push( - new PIXI.Point(points[i], points[i + 1]) - ); - } - - points = p; - } - - this.points = points; -}; - -/** - * Creates a clone of this polygon - * - * @method clone - * @return {Polygon} a copy of the polygon - */ -PIXI.Polygon.prototype.clone = function() -{ - var points = []; - for (var i=0; i y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if(intersect) inside = !inside; - } - - return inside; -}; - -// constructor -PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/core/Rectangle.js b/src/pixi/core/Rectangle.js deleted file mode 100644 index b8edfcc..0000000 --- a/src/pixi/core/Rectangle.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Mat Groves http://matgroves.com/ - */ - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class Rectangle - * @constructor - * @param x {Number} The X coord of the upper-left corner of the rectangle - * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall width of this rectangle - * @param height {Number} The overall height of this rectangle - */ -PIXI.Rectangle = function(x, y, width, height) -{ - /** - * @property x - * @type Number - * @default 0 - */ - this.x = x || 0; - - /** - * @property y - * @type Number - * @default 0 - */ - this.y = y || 0; - - /** - * @property width - * @type Number - * @default 0 - */ - this.width = width || 0; - - /** - * @property height - * @type Number - * @default 0 - */ - this.height = height || 0; -}; - -/** - * Creates a clone of this Rectangle - * - * @method clone - * @return {Rectangle} a copy of the rectangle - */ -PIXI.Rectangle.prototype.clone = function() -{ - return new PIXI.Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this Rectangle - * - * @method contains - * @param x {Number} The X coordinate of the point to test - * @param y {Number} The Y coordinate of the point to test - * @return {Boolean} Whether the x/y coords are within this Rectangle - */ -PIXI.Rectangle.prototype.contains = function(x, y) -{ - if(this.width <= 0 || this.height <= 0) - return false; - - var x1 = this.x; - if(x >= x1 && x <= x1 + this.width) - { - var y1 = this.y; - - if(y >= y1 && y <= y1 + this.height) - { - return true; - } - } - - return false; -}; - -// constructor -PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; - -PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index a6fcee3..be0e872 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -449,39 +449,67 @@ */ PIXI.DisplayObject.prototype.updateTransform = function() { - // TODO OPTIMIZE THIS!! with dirty - if(this.rotation !== this.rotationCache) - { + // create some matrix refs for easy access + var pt = this.parent.worldTransform; + var wt = this.worldTransform; - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); + // temporary matrix variables + var a, b, c, d, tx, ty; + + // TODO create a const for 2_PI + // so if rotation is between 0 then we can simplify the multiplication process.. + if(this.rotation % PIXI.PI_2) + { + // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + // get the matrix values of the displayobject based on its transform properties.. + a = this._cr * this.scale.x; + b = this._sr * this.scale.x; + c = -this._sr * this.scale.y; + d = this._cr * this.scale.y; + tx = this.position.x; + ty = this.position.y; + + // check for pivot.. not often used so geared towards that fact! + if(this.pivot.x || this.pivot.y) + { + tx -= this.pivot.x * a + this.pivot.y * c; + ty -= this.pivot.x * b + this.pivot.y * d; + } + + // concat the parent matrix with the objects transform. + wt.a = a * pt.a + b * pt.c; + wt.b = a * pt.b + b * pt.d; + wt.c = c * pt.a + d * pt.c; + wt.d = c * pt.b + d * pt.d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; + + + } + else + { + // lets do the fast version as we know there is no rotation.. + a = this.scale.x; + d = this.scale.y; + tx = this.position.x - this.pivot.x * a; + ty = this.position.y - this.pivot.y * d; + + wt.a = pt.a * a; + wt.b = pt.b * d; + wt.c = pt.c * a; + wt.d = pt.d * d; + wt.tx = tx * pt.a + ty * pt.c + pt.tx; + wt.ty = tx * pt.b + ty * pt.d + pt.ty; } - // var localTransform = this.localTransform//.toArray(); - var parentTransform = this.parent.worldTransform;//.toArray(); - var worldTransform = this.worldTransform;//.toArray(); - - var px = this.pivot.x; - var py = this.pivot.y; - - var a00 = this._cr * this.scale.x, - a01 = -this._sr * this.scale.y, - a10 = this._sr * this.scale.x, - a11 = this._cr * this.scale.y, - a02 = this.position.x - a00 * px - py * a01, - a12 = this.position.y - a11 * py - px * a10, - b00 = parentTransform.a, b01 = parentTransform.b, - b10 = parentTransform.c, b11 = parentTransform.d; - - worldTransform.a = b00 * a00 + b01 * a10; - worldTransform.b = b00 * a01 + b01 * a11; - worldTransform.tx = b00 * a02 + b01 * a12 + parentTransform.tx; - - worldTransform.c = b10 * a00 + b11 * a10; - worldTransform.d = b10 * a01 + b11 * a11; - worldTransform.ty = b10 * a02 + b11 * a12 + parentTransform.ty; - + // multiply the alphas.. this.worldAlpha = this.alpha * this.parent.worldAlpha; }; @@ -611,7 +639,11 @@ this._filters = null; this._cachedSprite.filters = tempFilters; - this._cachedSprite.texture.render(this, new PIXI.Point(-bounds.x, -bounds.y) ); + + PIXI.DisplayObject._tempMatrix.tx = -bounds.x; + PIXI.DisplayObject._tempMatrix.ty = -bounds.y; + + this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix ); this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); @@ -661,6 +693,9 @@ renderSession = renderSession; }; + +PIXI.DisplayObject._tempMatrix = new PIXI.Matrix(); + /** * The position of the displayObject on the x axis relative to the local coordinates of the parent. * @@ -690,3 +725,5 @@ this.position.y = value; } }); + + diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 7ad1ad5..93e4f5c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -216,7 +216,10 @@ */ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { - return this.removeChildAt( this.children.indexOf( child ) ); + var index = this.children.indexOf( child ); + if(index === -1)return; + + return this.removeChildAt( index ); }; /** @@ -278,8 +281,6 @@ */ PIXI.DisplayObjectContainer.prototype.updateTransform = function() { - //this._currentBounds = null; - if(!this.visible)return; PIXI.DisplayObject.prototype.updateTransform.call( this ); diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index cffecce..a39f49e 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -333,18 +333,18 @@ { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, - this.worldTransform.tx | 0, - this.worldTransform.ty | 0); + (this.worldTransform.tx* renderSession.resolution) | 0, + (this.worldTransform.ty* renderSession.resolution) | 0); } else { renderSession.context.setTransform( this.worldTransform.a, - this.worldTransform.c, this.worldTransform.b, + this.worldTransform.c, this.worldTransform.d, this.worldTransform.tx * renderSession.resolution, this.worldTransform.ty * renderSession.resolution); diff --git a/src/pixi/display/SpriteBatch.js b/src/pixi/display/SpriteBatch.js index c53833c..dd732f1 100644 --- a/src/pixi/display/SpriteBatch.js +++ b/src/pixi/display/SpriteBatch.js @@ -22,6 +22,8 @@ * @constructor * @param texture {Texture} */ + +//TODO RENAME to PARTICLE CONTAINER? PIXI.SpriteBatch = function(texture) { PIXI.DisplayObjectContainer.call( this); @@ -121,7 +123,7 @@ { if(isRotated) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); isRotated = false; } @@ -148,11 +150,11 @@ if (renderSession.roundPixels) { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx | 0, childTransform.ty | 0); } else { - context.setTransform(childTransform.a, childTransform.c, childTransform.b, childTransform.d, childTransform.tx, childTransform.ty); + context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, childTransform.tx, childTransform.ty); } context.drawImage(texture.baseTexture.source, diff --git a/src/pixi/extras/Strip.js b/src/pixi/extras/Strip.js index ad6d27d..8e79054 100644 --- a/src/pixi/extras/Strip.js +++ b/src/pixi/extras/Strip.js @@ -139,8 +139,17 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + this.renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -161,7 +170,16 @@ gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.texture.baseTexture, gl)); + + // check if a texture is dirty.. + if(this.texture.baseTexture._dirty[gl.id]) + { + renderSession.renderer.updateTexture(this.texture.baseTexture); + } + else + { + gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); + } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); @@ -184,11 +202,11 @@ if (renderSession.roundPixels) { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx | 0, transform.ty | 0); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); } else { - context.setTransform(transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } var strip = this; diff --git a/src/pixi/geom/Circle.js b/src/pixi/geom/Circle.js new file mode 100644 index 0000000..cc39a28 --- /dev/null +++ b/src/pixi/geom/Circle.js @@ -0,0 +1,85 @@ +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayObjects + * + * @class Circle + * @constructor + * @param x {Number} The X coordinate of the center of this circle + * @param y {Number} The Y coordinate of the center of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +}; + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +}; + +/** + * Checks whether the x, and y coordinates passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +}; + +/** +* Returns the framing rectangle of the circle as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Circle.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); +}; + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + diff --git a/src/pixi/geom/Ellipse.js b/src/pixi/geom/Ellipse.js new file mode 100644 index 0000000..b376333 --- /dev/null +++ b/src/pixi/geom/Ellipse.js @@ -0,0 +1,92 @@ +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayObjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coordinate of the center of the ellipse + * @param y {Number} The Y coordinate of the center of the ellipse + * @param width {Number} The half width of this ellipse + * @param height {Number} The half height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + var normx = ((x - this.x) / this.width), + normy = ((y - this.y) / this.height); + + normx *= normx; + normy *= normy; + + return (normx + normy <= 1); +}; + +/** +* Returns the framing rectangle of the ellipse as a PIXI.Rectangle object +* +* @method getBounds +* @return {Rectangle} the framing rectangle +*/ +PIXI.Ellipse.prototype.getBounds = function() +{ + return new PIXI.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); +}; + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; diff --git a/src/pixi/geom/Matrix.js b/src/pixi/geom/Matrix.js new file mode 100644 index 0000000..5e73cdd --- /dev/null +++ b/src/pixi/geom/Matrix.js @@ -0,0 +1,216 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Matrix class is now an object, which makes it a lot faster, + * here is a representation of it : + * | a | b | tx| + * | c | d | ty| + * | 0 | 0 | 1 | + * + * @class Matrix + * @constructor + */ +PIXI.Matrix = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +/** + * Creates a pixi matrix object based on the array given as a parameter + * + * @method fromArray + * @param array {Array} The array that the matrix will be filled with + */ +PIXI.Matrix.prototype.fromArray = function(array) +{ + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; +}; + +/** + * Creates an array from the current Matrix object + * + * @method toArray + * @param transpose {Boolean} Whether we need to transpose the matrix or not + * @return {Array} the newly created array which contains the matrix + */ +PIXI.Matrix.prototype.toArray = function(transpose) +{ + if(!this.array) this.array = new PIXI.Float32Array(9); + var array = this.array; + + if(transpose) + { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } + else + { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + + return array; +}; + +/** + * Get a new position with the current transormation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, transformed trough this matrix + */ +PIXI.Matrix.prototype.apply = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + newPos.x = this.a * pos.x + this.b * pos.y + this.tx; + newPos.y = this.c * pos.x + this.d * pos.y + this.ty; + + return newPos; +}; + +/** + * Get a new position with the inverse of the current transormation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * + * @method apply + * @param pos {Point} The origin + * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) + * @return {Point} The new point, inverse-transformed trough this matrix + */ +PIXI.Matrix.prototype.applyInverse = function(pos, newPos) +{ + newPos = newPos || new PIXI.Point(); + + var id = 1 / (this.a * this.d + this.b * -this.c); + newPos.x = this.d * id * pos.x - this.b * id * pos.y + (this.ty * this.b - this.tx * this.d) * id; + newPos.y = this.a * id * pos.y - this.c * id * pos.x + (this.tx * this.c - this.ty * this.a) * id; + + return newPos; +}; + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.translate = function(x, y) +{ + this.tx += x; + this.ty += y; + + return this; +}; + +/** + * Applies a scale transformation to the matrix. + * @method scale + * @param {Number} x The amount to scale horizontally + * @param {Number} y The amount to scale vertically + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.scale = function(x, y) +{ + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + + return this; +}; + + +/** + * Applies a rotation transformation to the matrix. + * @method rotate + * @param {Number} angle The angle in radians. + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.rotate = function(angle) +{ + var cos = Math.cos( angle ); + var sin = Math.sin( angle ); + + var a1 = this.a; + var c1 = this.c; + var tx1 = this.tx; + + this.a = a1 * cos-this.b * sin; + this.b = a1 * sin+this.b * cos; + this.c = c1 * cos-this.d * sin; + this.d = c1 * sin+this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + + return this; +}; + + +/** + * Translates the matrix on the x and y. + * @method translate + * @param {Number} x + * @param {Number} y + * @return {Matrix} This matrix. Good for chaining method calls. + **/ +PIXI.Matrix.prototype.append = function(matrix) +{ + var a1 = this.a; + var b1 = this.b; + var c1 = this.c; + var d1 = this.d; + + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + + return this; +}; + +PIXI.Matrix.prototype.identity = function() +{ + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; +}; + +PIXI.identityMatrix = new PIXI.Matrix(); diff --git a/src/pixi/geom/Point.js b/src/pixi/geom/Point.js new file mode 100644 index 0000000..202bc2f --- /dev/null +++ b/src/pixi/geom/Point.js @@ -0,0 +1,56 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point on the x axis + * @param y {Number} position of the point on the y axis + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +}; + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +}; + +/** + * Sets the point to a new x and y position. + * If y is ommited, both x and y will be set to x. + * + * @method set + * @param [x=0] {Number} position of the point on the x axis + * @param [y=0] {Number} position of the point on the y axis + */ +PIXI.Point.prototype.set = function(x, y) +{ + this.x = x || 0; + this.y = y || ( (y !== 0) ? this.x : 0 ) ; +}; + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; \ No newline at end of file diff --git a/src/pixi/geom/Polygon.js b/src/pixi/geom/Polygon.js new file mode 100644 index 0000000..d47c8a8 --- /dev/null +++ b/src/pixi/geom/Polygon.js @@ -0,0 +1,76 @@ +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array))points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(points[0] instanceof PIXI.Point) + { + var p = []; + for(var i = 0, il = points.length; i < il; i++) + { + p.push(points[i].x, points[i].y); + } + + points = p; + } + + this.closed = true; + this.points = points; +}; + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = this.points.slice(); + return new PIXI.Polygon(points); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this polygon + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coordinates are within this polygon + */ +PIXI.Polygon.prototype.contains = function(x, y) +{ + var inside = false; + + // use some raycasting to test hits + // https://github.com/substack/point-in-polygon/blob/master/index.js + var length = this.points.length / 2; + + for(var i = 0, j = length - 1; i < length; j = i++) + { + var xi = this.points[i * 2], yi = this.points[i * 2 + 1], + xj = this.points[j * 2], yj = this.points[j * 2 + 1], + intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +}; + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; diff --git a/src/pixi/geom/Rectangle.js b/src/pixi/geom/Rectangle.js new file mode 100644 index 0000000..b8edfcc --- /dev/null +++ b/src/pixi/geom/Rectangle.js @@ -0,0 +1,87 @@ +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +}; + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +}; + +/** + * Checks whether the x and y coordinates passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coordinate of the point to test + * @param y {Number} The Y coordinate of the point to test + * @return {Boolean} Whether the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +}; + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + +PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0); \ No newline at end of file diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index b31ce89..08062c4 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -77,8 +77,10 @@ * @type Object * @private */ - this.currentPath = {points:[]}; + this.currentPath = null; + + /** * Array containing some WebGL-related properties used by the WebGL renderer * @@ -168,16 +170,25 @@ */ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + if(this.currentPath) + { + if(this.currentPath.shape.points.length) + { + // halfway through a line? start a new one! + this.drawShape( new PIXI.Polygon( this.currentPath.shape.points.slice(-2) )); + return this; + } - this.graphicsData.push(this.currentPath); + // otherwise its empty so lets just set the line properties + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; + + } return this; }; @@ -191,14 +202,42 @@ */ PIXI.Graphics.prototype.moveTo = function(x, y) { - if (!this.currentPath.points.length) this.graphicsData.pop(); + this.drawShape(new PIXI.Polygon([x,y])); - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + /* + if(this.currentPath) + { + if(this.currentPath.shape.points.length > 2) + { + // halfway through a line? start a new one! + this.currentPath = this.drawShape( new PIXI.Polygon( x, y ); + return this; + } + else + { + // reuse existing path! + this.currentPath.shape.points = [x,y]; + this.currentPath.lineWidth = this.lineWidth; + this.currentPath.lineColor = this.lineColor; + this.currentPath.lineAlpha = this.lineAlpha; - this.currentPath.points.push(x, y); + return this + } + } + + this.currentPath = this.drawShape(new PIXI.Polygon([x,y])) - this.graphicsData.push(this.currentPath); + this.currentPath.push(x, y); +`*/ + + // if (!this.currentPath.points.length) this.graphicsData.pop(); + + //// this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + // fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + //this.currentPath.points.push(x, y); + + // this.graphicsData.push(this.currentPath); return this; }; @@ -213,7 +252,7 @@ */ PIXI.Graphics.prototype.lineTo = function(x, y) { - this.currentPath.points.push(x, y); + this.currentPath.shape.points.push(x, y); this.dirty = true; return this; @@ -232,12 +271,19 @@ */ PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var xa, ya, n = 20, - points = this.currentPath.points; + points = this.currentPath.shape.points; if(points.length === 0)this.moveTo(0, 0); @@ -276,7 +322,14 @@ */ PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) { - if( this.currentPath.points.length === 0)this.moveTo(0,0); + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; + } + else + { + this.moveTo(0,0); + } var n = 20, dt, @@ -284,7 +337,7 @@ dt3, t2, t3, - points = this.currentPath.points; + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -327,10 +380,19 @@ */ PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) { + if( this.currentPath ) + { + if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [x1, y1]; + } + else + { + this.moveTo(x1, y1); + } + // check that path contains subpaths - if( this.currentPath.points.length === 0)this.moveTo(x1, y1); + if( this.currentPath.length === 0)this.moveTo(x1, y1); - var points = this.currentPath.points; + var points = this.currentPath; var fromX = points[points.length-2]; var fromY = points[points.length-1]; @@ -390,12 +452,12 @@ var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - var points = this.currentPath.points; + var points = this.currentPath.shape.points; if(points.length !== 0 && points[points.length-2] !== startX || points[points.length-1] !== startY) { this.moveTo(startX, startY); - points = this.currentPath.points; + points = this.currentPath.shape.points; } if (startAngle === endAngle)return this; @@ -443,28 +505,6 @@ return this; }; -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * the current drawing position is then set to (x, y). - * - * @method lineTo - * @param x {Number} the X coordinate to draw to - * @param y {Number} the Y coordinate to draw to - */ -PIXI.Graphics.prototype.drawPath = function(path) -{ - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - - this.graphicsData.push(this.currentPath); - - this.currentPath.points = this.currentPath.points.concat(path); - this.dirty = true; - - return this; -}; /** * Specifies a simple one-color fill that subsequent calls to other Graphics methods @@ -479,8 +519,17 @@ this.filling = true; this.fillColor = color || 0; - this.fillAlpha = (arguments.length < 2) ? 1 : alpha; + this.fillAlpha = (alpha === undefined) ? 1 : alpha; + if(this.currentPath) + { + if(this.currentPath.shape.points.length <= 2) + { + this.currentPath.fill = this.filling; + this.currentPath.fillColor = this.fillColor; + this.currentPath.fillAlpha = this.fillAlpha; + } + } return this; }; @@ -508,14 +557,7 @@ */ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.RECT}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Rectangle(x,y, width, height)); return this; }; @@ -528,21 +570,21 @@ * @param width {Number} The width of the rectangle * @param height {Number} The height of the rectangle * @param radius {Number} Radius of the rectangle corners - */ + *//* PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) { if (!this.currentPath.points.length) this.graphicsData.pop(); - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height, radius], type:PIXI.Graphics.RREC}; + // this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + /// fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + // points:[x, y, width, height, radius], shape:new PIXI.Rectangle(x,y, width, height), type:PIXI.Graphics.RREC}; this.graphicsData.push(this.currentPath); this.dirty = true; return this; }; - +*/ /** * Draws a circle. * @@ -553,15 +595,7 @@ */ PIXI.Graphics.prototype.drawCircle = function(x, y, radius) { - - if (!this.currentPath.points.length) this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; + this.drawShape(new PIXI.Circle(x,y, radius)); return this; }; @@ -577,16 +611,23 @@ */ PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) { + this.drawShape(new PIXI.Ellipse(x, y, width, height)); - if (!this.currentPath.points.length) this.graphicsData.pop(); + return this; +}; - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, - points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - - this.graphicsData.push(this.currentPath); - this.dirty = true; - +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coordinate to draw to + * @param y {Number} the Y coordinate to draw to + */ +PIXI.Graphics.prototype.drawPolygon = function(path) +{ + if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); + this.drawShape(new PIXI.Polygon(path)); return this; }; @@ -742,8 +783,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); @@ -846,21 +887,21 @@ var minY = Infinity; var maxY = -Infinity; - var points, x, y, w, h; + var shape, points, x, y, w, h; for (var i = 0; i < this.graphicsData.length; i++) { var data = this.graphicsData[i]; var type = data.type; var lineWidth = data.lineWidth; - - points = data.points; + shape = data.shape; + if(type === PIXI.Graphics.RECT) { - x = points[0] - lineWidth/2; - y = points[1] - lineWidth/2; - w = points[2] + lineWidth; - h = points[3] + lineWidth; + x = shape.x - lineWidth/2; + y = shape.y - lineWidth/2; + w = shape.width + lineWidth; + h = shape.height + lineWidth; minX = x < minX ? x : minX; maxX = x + w > maxX ? x + w : maxX; @@ -868,12 +909,25 @@ minY = y < minY ? y : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC || type === PIXI.Graphics.ELIP) + else if(type === PIXI.Graphics.CIRC) { - x = points[0]; - y = points[1]; - w = points[2] + lineWidth/2; - h = points[3] + lineWidth/2; + x = shape.x; + y = shape.y; + w = shape.radius + lineWidth/2; + h = shape.radius + lineWidth/2; + + minX = x - w < minX ? x - w : minX; + maxX = x + w > maxX ? x + w : maxX; + + minY = y - h < minY ? y - h : minY; + maxY = y + h > maxY ? y + h : maxY; + } + else if(type === PIXI.Graphics.ELIP) + { + x = shape.x; + y = shape.y; + w = shape.width + lineWidth/2; + h = shape.height + lineWidth/2; minX = x - w < minX ? x - w : minX; maxX = x + w > maxX ? x + w : maxX; @@ -884,6 +938,8 @@ else { // POLY + points = shape.points; + for (var j = 0; j < points.length; j+=2) { @@ -950,6 +1006,46 @@ this._cachedSprite = null; }; +PIXI.Graphics.prototype.drawShape = function(shape) +{ + if(this.currentPath) + { + // check current path! + if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + } + + this.currentPath = null; + + var data = new PIXI.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + + this.graphicsData.push(data); + + if(data.type === PIXI.Graphics.POLY) + { + data.shape.closed = this.filling; + this.currentPath = data; + } + + this.dirty = true; + + return data; + +}; + +PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) +{ + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + // SOME TYPES: PIXI.Graphics.POLY = 0; @@ -958,3 +1054,9 @@ PIXI.Graphics.ELIP = 3; PIXI.Graphics.RREC = 4; + +PIXI.Polygon.prototype.type = PIXI.Graphics.POLY; +PIXI.Rectangle.prototype.type = PIXI.Graphics.RECT; +PIXI.Circle.prototype.type = PIXI.Graphics.CIRC; +PIXI.Ellipse.prototype.type = PIXI.Graphics.ELIP; + diff --git a/src/pixi/renderers/canvas/CanvasGraphics.js b/src/pixi/renderers/canvas/CanvasGraphics.js index 0daa444..9fe4194 100644 --- a/src/pixi/renderers/canvas/CanvasGraphics.js +++ b/src/pixi/renderers/canvas/CanvasGraphics.js @@ -31,7 +31,7 @@ for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - var points = data.points; + var shape = data.shape; context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); @@ -41,6 +41,8 @@ { context.beginPath(); + var points = shape.points; + context.moveTo(points[0], points[1]); for (var j=1; j < points.length/2; j++) @@ -48,6 +50,11 @@ context.lineTo(points[j * 2], points[j * 2 + 1]); } + if(shape.closed) + { + context.lineTo(points[0], points[1]); + } + // if the first and last point are the same close the path - much neater :) if(points[0] === points[points.length-2] && points[1] === points[points.length-1]) { @@ -73,13 +80,13 @@ { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); - context.fillRect(points[0], points[1], points[2], points[3]); + context.fillRect(shape.x, shape.y, shape.width, shape.height); } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeRect(points[0], points[1], points[2], points[3]); + context.strokeRect(shape.x, shape.y, shape.width, shape.height); } } @@ -87,7 +94,7 @@ { // TODO - need to be Undefined! context.beginPath(); - context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); context.closePath(); if(data.fill) @@ -107,13 +114,11 @@ // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - var ellipseData = data.points; + var w = shape.width * 2; + var h = shape.height * 2; - var w = ellipseData[2] * 2; - var h = ellipseData[3] * 2; - - var x = ellipseData[0] - w/2; - var y = ellipseData[1] - h/2; + var x = shape.x - w/2; + var y = shape.y - h/2; context.beginPath(); @@ -145,6 +150,7 @@ context.stroke(); } } + /* else if (data.type === PIXI.Graphics.RREC) { var rx = points[0]; @@ -181,6 +187,7 @@ context.stroke(); } } + */ } }; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 81ea948..6c6f728 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -203,10 +203,6 @@ */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update textures if need be - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - stage.updateTransform(); this.context.setTransform(1,0,0,1,0,0); @@ -241,12 +237,6 @@ } } - // remove frame updates.. // removeing for now... - // TODO remove this eventually! - if(PIXI.Texture.frameUpdates.length > 0) - { - PIXI.Texture.frameUpdates.length = 0; - } }; /** diff --git a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js index 10a5f82..0c0d5bc 100644 --- a/src/pixi/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/pixi/renderers/canvas/utils/CanvasMaskManager.js @@ -31,8 +31,8 @@ var resolution = renderSession.resolution; context.setTransform(transform.a * resolution, - transform.c * resolution, transform.b * resolution, + transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 3ed5737..4fef08c 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -99,13 +99,13 @@ this.view = options.view || document.createElement( 'canvas' ); // deal with losing context.. - this.contextLostFunction = this.handleContextLost.bind(this); - this.contextRestoredFunction = this.handleContextRestored.bind(this); + this.contextLostBound = this.handleContextLost.bind(this); + this.contextRestoredBound = this.handleContextRestored.bind(this); - this.view.addEventListener('webglcontextlost', this.contextLostFunction, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredFunction, false); + this.view.addEventListener('webglcontextlost', this.contextLostBound, false); + this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - this.contextOptions = { + this._contextOptions = { alpha: this.transparent, antialias: options.antialias, // SPEED UP?? premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', @@ -113,62 +113,16 @@ preserveDrawingBuffer: options.preserveDrawingBuffer }; - var gl = null; - - ['experimental-webgl', 'webgl'].forEach(function(name) { - try { - gl = gl || this.view.getContext(name, this.contextOptions); - } catch(e) {} - }, this); - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer' + this); - } - - this.gl = gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; - - PIXI.glContexts[this.glContextId] = gl; - - if(!PIXI.blendModesWebGL) - { - PIXI.blendModesWebGL = []; - - PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } - this.projection = new PIXI.Point(); - this.offset = new PIXI.Point(0, 0); - this.resize(width, height); - - this.contextLost = false; - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager = new PIXI.WebGLShaderManager(gl); // deals with managing the shader programs and their attribs - this.spriteBatch = new PIXI.WebGLSpriteBatch(gl); // manages the rendering of sprites - this.maskManager = new PIXI.WebGLMaskManager(gl); // manages the masks using the stencil buffer - this.filterManager = new PIXI.WebGLFilterManager(gl, this.transparent); // manages the filters - this.stencilManager = new PIXI.WebGLStencilManager(gl); - this.blendModeManager = new PIXI.WebGLBlendModeManager(gl); + this.shaderManager = new PIXI.WebGLShaderManager(); // deals with managing the shader programs and their attribs + this.spriteBatch = new PIXI.WebGLSpriteBatch(); // manages the rendering of sprites + this.maskManager = new PIXI.WebGLMaskManager(); // manages the masks using the stencil buffer + this.filterManager = new PIXI.WebGLFilterManager(); // manages the filters + this.stencilManager = new PIXI.WebGLStencilManager(); // manages the stencil buffer + this.blendModeManager = new PIXI.WebGLBlendModeManager(); // manages the blendModes // TODO remove this.renderSession = {}; @@ -183,16 +137,50 @@ this.renderSession.renderer = this; this.renderSession.resolution = this.resolution; - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + // time init the context.. + this.initContext(); - gl.colorMask(true, true, true, true);//this.transparent); + // map some webGL blend modes.. + this.mapBlendModes(); }; // constructor PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; +PIXI.WebGLRenderer.prototype.initContext = function() +{ + var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); + this.gl = gl; + + if (!gl) { + // fail, not able to get a context + throw new Error('This browser does not support webGL. Try using the canvas renderer'); + } + + this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + + PIXI.glContexts[this.glContextId] = gl; + + // set up the default pixi settings.. + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + gl.enable(gl.BLEND); + + // need to set the context for all the managers... + this.shaderManager.setContext(gl); + this.spriteBatch.setContext(gl); + this.maskManager.setContext(gl); + this.filterManager.setContext(gl); + this.blendModeManager.setContext(gl); + this.stencilManager.setContext(gl); + + this.renderSession.gl = this.gl; + + // now resize and we are good to go! + this.resize(this.width, this.height); +}; + + /** * Renders the stage to its webGL view * @@ -201,9 +189,9 @@ */ PIXI.WebGLRenderer.prototype.render = function(stage) { + // no point rendering if our context has been blown up! if(this.contextLost)return; - // if rendering a new stage clear the batches.. if(this.__stage !== stage) { @@ -214,48 +202,15 @@ this.__stage = stage; } - // update any textures this includes uvs and uploading them to the gpu - PIXI.WebGLRenderer.updateTextures(); - // update the scene graph stage.updateTransform(); - // interaction - if(stage._interactive) - { - //need to add some events! - if(!stage._interactiveEventsAdded) - { - stage._interactiveEventsAdded = true; - stage.interactionManager.setTarget( this ); - } - } - var gl = this.gl; - // -- Does this need to be set every frame? -- // - //gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if(this.transparent) - { - gl.clearColor(0, 0, 0, 0); - } - else - { - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderDisplayObject( stage, this.projection ); - + // interaction - if(stage.interactive) + if(stage._interactive) { //need to add some events! if(!stage._interactiveEventsAdded) @@ -273,26 +228,24 @@ } } - /* - //can simulate context loss in Chrome like so: - this.view.onmousedown = function(ev) { - console.dir(this.gl.getSupportedExtensions()); - var ext = ( - gl.getExtension("WEBGL_scompressed_texture_s3tc") - // gl.getExtension("WEBGL_compressed_texture_s3tc") || - // gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || - // gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") - ); - console.dir(ext); - var loseCtx = this.gl.getExtension("WEBGL_lose_context"); - console.log("killing context"); - loseCtx.loseContext(); - setTimeout(function() { - console.log("restoring context..."); - loseCtx.restoreContext(); - }.bind(this), 1000); - }.bind(this); - */ + // -- Does this need to be set every frame? -- // + gl.viewport(0, 0, this.width, this.height); + + // make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + if(this.transparent) + { + gl.clearColor(0, 0, 0, 0); + } + else + { + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); + } + + gl.clear(gl.COLOR_BUFFER_BIT); + + this.renderDisplayObject( stage, this.projection ); }; /** @@ -306,11 +259,14 @@ PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer) { this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL); + // reset the render session data.. this.renderSession.drawCount = 0; - this.renderSession.currentBlendMode = 9999; + // set the default projection this.renderSession.projection = projection; + + //set the default offset this.renderSession.offset = this.offset; // start the sprite batch @@ -327,66 +283,6 @@ }; /** - * Updates the textures loaded into this webgl renderer - * - * @static - * @method updateTextures - * @private - */ -PIXI.WebGLRenderer.updateTextures = function() -{ - var i = 0; - - for (i=0; i < PIXI.Texture.frameUpdates.length; i++) - PIXI.WebGLRenderer.updateTextureFrame(PIXI.Texture.frameUpdates[i]); - - for (i = 0; i < PIXI.texturesToDestroy.length; i++) - PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - - PIXI.texturesToUpdate.length = 0; - PIXI.texturesToDestroy.length = 0; - PIXI.Texture.frameUpdates.length = 0; -}; - -/** - * Destroys a loaded webgl texture - * - * @method destroyTexture - * @param texture {Texture} The texture to update - * @private - */ -PIXI.WebGLRenderer.destroyTexture = function(texture) -{ - //TODO break this out into a texture manager... - - for (var i = texture._glTextures.length - 1; i >= 0; i--) - { - var glTexture = texture._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if(gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - texture._glTextures.length = 0; -}; - -/** - * - * @method updateTextureFrame - * @param texture {Texture} The texture to update the frame from - * @private - */ -PIXI.WebGLRenderer.updateTextureFrame = function(texture) -{ - // now set the uvs. Figured that the uv data sits with a texture rather than a sprite. - // so uv data is stored on the texture itself - texture._updateWebGLuvs(); -}; - -/** * resizes the webGL view to the specified width and height * * @method resize @@ -401,8 +297,8 @@ this.view.width = this.width; this.view.height = this.height; - this.view.style.width = width + 'px'; - this.view.style.height = height + 'px'; + // this.view.style.width = width + 'px'; + // this.view.style.height = height + 'px'; // console.log(this.width / this.resolution) this.gl.viewport(0, 0, this.width, this.height); @@ -412,87 +308,45 @@ }; /** - * Creates a WebGL texture + * Updates and Creates a WebGL texture for the renderers context * - * @method createWebGLTexture + * @method updateTexture * @param texture {Texture} the texture to render - * @param gl {webglContext} the WebGL context - * @static */ -PIXI.createWebGLTexture = function(texture, gl) +PIXI.WebGLRenderer.prototype.updateTexture = function(texture) { + if(!texture.hasLoaded)return; + var gl = this.gl; - if(texture.hasLoaded) + if(!texture._glTextures[gl.id])texture._glTextures[gl.id] = gl.createTexture(); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + // reguler... + if(!texture._powerOf2) { - texture._glTextures[gl.id] = gl.createTexture(); - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - gl.bindTexture(gl.TEXTURE_2D, null); - - texture._dirty[gl.id] = false; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + texture._dirty[gl.id] = false; return texture._glTextures[gl.id]; }; /** - * Updates a WebGL texture - * - * @method updateWebGLTexture - * @param texture {Texture} the texture to update - * @param gl {webglContext} the WebGL context - * @private - */ -PIXI.updateWebGLTexture = function(texture, gl) -{ - if( texture._glTextures[gl.id] ) - { - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - // reguler... - - if(!texture._powerOf2) - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else - { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - texture._dirty[gl.id] = false; - } - -}; - -/** * Handles a lost webgl context * * @method handleContextLost @@ -514,60 +368,16 @@ */ PIXI.WebGLRenderer.prototype.handleContextRestored = function() { + this.initContext(); - //try 'experimental-webgl' - try { - this.gl = this.view.getContext('experimental-webgl', this.contextOptions); - } catch (e) { - //try 'webgl' - try { - this.gl = this.view.getContext('webgl', this.contextOptions); - } catch (e2) { - // fail, not able to get a context - throw new Error(' This browser does not support webGL. Try using the canvas renderer' + this); - } - } - - PIXI.glContexts[this.glContextId] = null; - - var gl = this.gl; - this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++; - - PIXI.glContexts[this.glContextId] = gl; - - - - // need to set the context... - this.shaderManager.setContext(gl); - this.spriteBatch.setContext(gl); - // this.primitiveBatch.setContext(gl); - this.maskManager.setContext(gl); - this.filterManager.setContext(gl); - - - this.renderSession.gl = this.gl; - - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - - gl.enable(gl.BLEND); - gl.colorMask(true, true, true, true);//this.transparent); - - this.gl.viewport(0, 0, this.width, this.height); - + // empty all the ol gl textures as they are useless now for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTextures = []; } - - /** - * Whether the context was lost - * @property contextLost - * @type Boolean - */ + this.contextLost = false; - }; /** @@ -577,12 +387,9 @@ */ PIXI.WebGLRenderer.prototype.destroy = function() { - - // deal with losing context.. - // remove listeners - this.view.off('webglcontextlost', this.contextLostFunction); - this.view.off('webglcontextrestored', this.contextRestoredFunction); + this.view.off('webglcontextlost', this.contextLostBound); + this.view.off('webglcontextrestored', this.contextRestoredBound); PIXI.glContexts[this.glContextId] = null; @@ -604,5 +411,32 @@ this.renderSession = null; }; +PIXI.WebGLRenderer.prototype.mapBlendModes = function() +{ + var gl = this.gl; + + if(!PIXI.blendModesWebGL) + { + PIXI.blendModesWebGL = []; + + PIXI.blendModesWebGL[PIXI.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; + PIXI.blendModesWebGL[PIXI.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + PIXI.blendModesWebGL[PIXI.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + } +}; PIXI.WebGLRenderer.glContextId = 0; diff --git a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js index 653019f..c73728f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLBlendModeManager.js @@ -8,10 +8,14 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLBlendModeManager = function(gl) +PIXI.WebGLBlendModeManager = function() +{ + this.currentBlendMode = 99999; +}; + +PIXI.WebGLBlendModeManager.prototype.setContext = function(gl) { this.gl = gl; - this.currentBlendMode = 99999; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js index e296251..0d08e47 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js @@ -8,7 +8,7 @@ * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java */ -PIXI.WebGLFastSpriteBatch = function(gl) +PIXI.WebGLFastSpriteBatch = function() { @@ -53,7 +53,7 @@ this.matrix = null; - this.setContext(gl); + //this.setContext(gl); }; PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js index 7383072..278e7f4 100644 --- a/src/pixi/renderers/webgl/utils/WebGLFilterManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLFilterManager.js @@ -6,19 +6,16 @@ * @class WebGLFilterManager * @constructor * @param gl {WebGLContext} the current WebGL drawing context -* @param transparent {Boolean} Whether or not the drawing context should be transparent * @private */ -PIXI.WebGLFilterManager = function(gl, transparent) +PIXI.WebGLFilterManager = function() { - this.transparent = transparent; - this.filterStack = []; this.offsetX = 0; this.offsetY = 0; - this.setContext(gl); + // this.setContext(gl); }; // API diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index 1b63e8d..4de401d 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -131,12 +131,25 @@ { var data = graphics.graphicsData[i]; + + if(data.type === PIXI.Graphics.POLY) { + // need to add the points the the graphics object.. + data.points = data.shape.points.slice(); + if(data.shape.closed) + { + // close the poly if the valu is true! + if(data.points[0] !== data.points[data.points.length-2] && data.points[1] !== data.points[data.points.length-1]) + { + data.points.push(data.points[0], data.points[1]); + } + } + // MAKE SURE WE HAVE THE CORRECT TYPE.. if(data.fill) { - if(data.points.length > 6) + if(data.points.length >= 6) { if(data.points.length > 5 * 2) { @@ -230,12 +243,11 @@ // --- // // need to convert points to a nice regular data // - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; - + var rectData = graphicsData.shape; + var x = rectData.x; + var y = rectData.y; + var width = rectData.width; + var height = rectData.height; if(graphicsData.fill) { @@ -417,13 +429,24 @@ */ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { - // need to convert points to a nice regular data - var rectData = graphicsData.points; - var x = rectData[0]; - var y = rectData[1]; - var width = rectData[2]; - var height = rectData[3]; + var circleData = graphicsData.shape; + var x = circleData.x; + var y = circleData.y; + var width; + var height; + + // TODO - bit hacky?? + if(graphicsData.type === PIXI.Graphics.CIRC) + { + width = circleData.radius; + height = circleData.radius; + } + else + { + width = circleData.width; + height = circleData.height; + } var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; @@ -491,7 +514,6 @@ { // TODO OPTIMISE! var i = 0; - var points = graphicsData.points; if(points.length === 0)return; @@ -757,8 +779,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; - if(points.length < 6)return; + if(points.length < 6)return; // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index b40efaf..181f560 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -8,9 +8,9 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLMaskManager = function(gl) +PIXI.WebGLMaskManager = function() { - this.setContext(gl); + //this.setContext(gl); }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js index 626ac21..d342e03 100644 --- a/src/pixi/renderers/webgl/utils/WebGLShaderManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLShaderManager.js @@ -8,7 +8,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLShaderManager = function(gl) +PIXI.WebGLShaderManager = function() { this.maxAttibs = 10; @@ -19,7 +19,7 @@ this.attribState[i] = false; } - this.setContext(gl); + //this.setContext(gl); // the final one is used for the rendering strips }; diff --git a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js index e30cd4f..b74c5e4 100755 --- a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js +++ b/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js @@ -16,7 +16,7 @@ * @param gl {WebGLContext} the current WebGL drawing context * */ -PIXI.WebGLSpriteBatch = function(gl) +PIXI.WebGLSpriteBatch = function() { /** @@ -75,7 +75,7 @@ this.currentBatchSize = 0; this.currentBaseTexture = null; - this.setContext(gl); +// this.setContext(gl); this.dirty = true; @@ -198,12 +198,12 @@ var worldTransform = sprite.worldTransform; - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;///[5]; + var a = worldTransform.a / resolution; + var b = worldTransform.b / resolution; + var c = worldTransform.c / resolution; + var d = worldTransform.d / resolution; + var tx = worldTransform.tx; + var ty = worldTransform.ty; // xy verticies[index++] = a * w1 + c * h1 + tx; @@ -325,8 +325,8 @@ var worldTransform = tilingSprite.worldTransform; var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.c / resolution;//[3]; - var c = worldTransform.b / resolution;//[1]; + var b = worldTransform.b / resolution;//[3]; + var c = worldTransform.c / resolution;//[1]; var d = worldTransform.d / resolution;//[4]; var tx = worldTransform.tx;//[2]; var ty = worldTransform.ty;///[5]; @@ -412,7 +412,6 @@ gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0); gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4); - } // upload the verts to the buffer @@ -432,13 +431,15 @@ var currentBaseTexture = null; var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode; + var blendSwap = false; for (var i = 0, j = this.currentBatchSize; i < j; i++) { nextTexture = this.textures[i]; nextBlendMode = this.blendModes[i]; + blendSwap = currentBlendMode !== nextBlendMode; - if(currentBaseTexture !== nextTexture || currentBlendMode !== nextBlendMode) + if(currentBaseTexture !== nextTexture || blendSwap) { this.renderBatch(currentBaseTexture, batchSize, start); @@ -447,7 +448,7 @@ currentBaseTexture = nextTexture; currentBlendMode = nextBlendMode; - this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); + if( blendSwap )this.renderSession.blendModeManager.setBlendMode( currentBlendMode ); } batchSize++; @@ -464,14 +465,18 @@ if(size === 0)return; var gl = this.gl; - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id] || PIXI.createWebGLTexture(texture, gl)); // check if a texture is dirty.. if(texture._dirty[gl.id]) { - PIXI.updateWebGLTexture(this.currentBaseTexture, gl); + this.renderSession.renderer.updateTexture(texture); } + else + { + // bind the current texture + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + } + // now draw those suckas! gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); @@ -488,6 +493,7 @@ PIXI.WebGLSpriteBatch.prototype.stop = function() { this.flush(); + this.dirty = true; }; /** diff --git a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js index b7c6cb9..f841e6f 100644 --- a/src/pixi/renderers/webgl/utils/WebGLStencilManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLStencilManager.js @@ -8,11 +8,11 @@ * @param gl {WebGLContext} the current WebGL drawing context * @private */ -PIXI.WebGLStencilManager = function(gl) +PIXI.WebGLStencilManager = function() { this.stencilStack = []; - this.setContext(gl); + //this.setContext(gl); this.reverse = true; this.count = 0; @@ -269,8 +269,6 @@ } - - //renderSession.shaderManager.deactivatePrimitiveShader(); }; /** diff --git a/src/pixi/text/Text.js b/src/pixi/text/Text.js index 3f94b5d..ba05f6e 100644 --- a/src/pixi/text/Text.js +++ b/src/pixi/text/Text.js @@ -295,6 +295,9 @@ this._width = this.canvas.width; this._height = this.canvas.height; + // update the dirty base textures + this.texture.baseTexture.dirty(); + }; /** @@ -313,7 +316,7 @@ this.updateText(); this.dirty = false; - PIXI.updateWebGLTexture(this.texture.baseTexture, renderSession.gl); + } PIXI.Sprite.prototype._renderWebGL.call(this, renderSession); diff --git a/src/pixi/textures/BaseTexture.js b/src/pixi/textures/BaseTexture.js index 5f954e2..ed2705f 100644 --- a/src/pixi/textures/BaseTexture.js +++ b/src/pixi/textures/BaseTexture.js @@ -3,8 +3,6 @@ */ PIXI.BaseTextureCache = {}; -PIXI.texturesToUpdate = []; -PIXI.texturesToDestroy = []; PIXI.BaseTextureCacheIdGenerator = 0; @@ -87,9 +85,10 @@ // used for webGL this._glTextures = []; - // used for webGL texture updating... - this._dirty = []; + // TODO - this needs to be addressed + this._dirty = [true, true, true, true]; + if(!source)return; @@ -98,8 +97,7 @@ this.hasLoaded = true; this.width = this.source.naturalWidth || this.source.width; this.height = this.source.naturalHeight || this.source.height; - - PIXI.texturesToUpdate.push(this); + this.dirty(); } else { @@ -111,10 +109,7 @@ scope.width = scope.source.naturalWidth || scope.source.width; scope.height = scope.source.naturalHeight || scope.source.height; - for (var i = 0; i < scope._glTextures.length; i++) - { - scope._dirty[i] = true; - } + scope.dirty(); // add it to somewhere... scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -153,7 +148,20 @@ delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; - PIXI.texturesToDestroy.push(this); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; }; /** @@ -169,6 +177,14 @@ this.source.src = newSrc; }; +PIXI.BaseTexture.prototype.dirty = function() +{ + for (var i = 0; i < this._glTextures.length; i++) + { + this._dirty[i] = true; + } +}; + /** * Helper function that returns a base texture based on an image url * If the image is not in the base texture cache it will be created and loaded diff --git a/src/pixi/textures/RenderTexture.js b/src/pixi/textures/RenderTexture.js index edb86cf..b5c4577 100644 --- a/src/pixi/textures/RenderTexture.js +++ b/src/pixi/textures/RenderTexture.js @@ -118,9 +118,8 @@ } this.valid = true; - PIXI.Texture.frameUpdates.push(this); - + this._updateUvs(); }; PIXI.RenderTexture.prototype = Object.create(PIXI.Texture.prototype); @@ -136,10 +135,7 @@ */ PIXI.RenderTexture.prototype.resize = function(width, height, updateBase) { - if (width === this.width && height === this.height) - { - return; - } + if (width === this.width && height === this.height)return; this.valid = (width > 0 && height > 0); @@ -189,13 +185,31 @@ * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn * @private */ -PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, matrix, clear) { if(!this.valid)return; //TOOD replace position with matrix.. - var gl = this.renderer.gl; + + //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix + var wt = displayObject.worldTransform; + wt.identity(); + wt.translate(0, this.projection.y * 2); + if(matrix)wt.append(matrix); + wt.scale(1,-1); - gl.colorMask(true, true, true, true); + // setWorld Alpha to ensure that the object is renderer at full opacity + displayObject.worldAlpha = 1; + + // Time to update all the children of the displayObject with the new matrix.. + var children = displayObject.children; + + for(var i=0,j=children.length; i