diff --git a/README.md b/README.md index 3dbcae4..f11798f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - [x] `filters/` - [x] `geom/` (move to `math/`) - [x] `loaders/` -- [ ] `primitives/` +- [x] `primitives/` - [ ] `renderers/` - [ ] `text/` - [ ] `textures/` diff --git a/README.md b/README.md index 3dbcae4..f11798f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - [x] `filters/` - [x] `geom/` (move to `math/`) - [x] `loaders/` -- [ ] `primitives/` +- [x] `primitives/` - [ ] `renderers/` - [ ] `text/` - [ ] `textures/` diff --git a/src/primitives/Graphics.js b/src/primitives/Graphics.js index 91a44ea..e738d01 100644 --- a/src/primitives/Graphics.js +++ b/src/primitives/Graphics.js @@ -1,41 +1,43 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ +var GraphicsData = require('./GraphicsData'), + Sprite = require('../display/Sprite'), + DisplayObjectContainer = require('../display/DisplayObjectContainer'), + CanvasGraphics = require('../renderers/canvas/CanvasGraphics'), + CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + math = require('../math'); /** - * The Graphics class contains methods used to draw primitive shapes such as lines, circles and rectangles to the display, and color and fill them. - * - * @class Graphics + * The Graphics class contains methods used to draw primitive shapes such as lines, circles and + * rectangles to the display, and color and fill them. + * + * @class * @extends DisplayObjectContainer - * @constructor + * @namespace PIXI */ -PIXI.Graphics = function() -{ - PIXI.DisplayObjectContainer.call( this ); +function Graphics() { + DisplayObjectContainer.call(this); this.renderable = true; /** * The alpha value used when filling the Graphics object. * - * @property fillAlpha - * @type Number + * @member {number} + * @default 1 */ this.fillAlpha = 1; /** * The width (thickness) of any lines drawn. * - * @property lineWidth - * @type Number + * @member {number} + * @default 0 */ this.lineWidth = 0; /** * The color of any lines drawn. * - * @property lineColor - * @type String + * @member {string} * @default 0 */ this.lineColor = 0; @@ -43,8 +45,7 @@ /** * Graphics data * - * @property graphicsData - * @type Array + * @member {object[]} * @private */ this.graphicsData = []; @@ -52,35 +53,31 @@ /** * The tint applied to the graphic shape. This is a hex value. Apply a value of 0xFFFFFF to reset the tint. * - * @property tint - * @type Number + * @member {number} * @default 0xFFFFFF */ this.tint = 0xFFFFFF; /** - * The blend mode to be applied to the graphic shape. Apply a value of PIXI.blendModes.NORMAL to reset the blend mode. + * The blend mode to be applied to the graphic shape. Apply a value of blendModes.NORMAL to reset the blend mode. * - * @property blendMode - * @type Number - * @default PIXI.blendModes.NORMAL; + * @member {number} + * @default blendModes.NORMAL; */ - this.blendMode = PIXI.blendModes.NORMAL; - + this.blendMode = blendModes.NORMAL; + /** * Current path * - * @property currentPath - * @type Object + * @member {object} * @private */ this.currentPath = null; - + /** * Array containing some WebGL-related properties used by the WebGL renderer. * - * @property _webGL - * @type Array + * @member {object[]} * @private */ this._webGL = []; @@ -88,44 +85,47 @@ /** * Whether this shape is being used as a mask. * - * @property isMask - * @type Boolean + * @member {boolean} */ this.isMask = false; /** * The bounds' padding used for bounds calculation. * - * @property boundsPadding - * @type Number + * @member {number} */ this.boundsPadding = 0; - this._localBounds = new PIXI.Rectangle(0,0,1,1); + /** + * A cache of the local bounds to prevent recalculation. + * + * @member {REctangle} + * @private + */ + this._localBounds = new Rectangle(0,0,1,1); /** - * Used to detect if the graphics object has changed. If this is set to true then the graphics object will be recalculated. - * - * @property dirty - * @type Boolean + * Used to detect if the graphics object has changed. If this is set to true then the graphics + * object will be recalculated. + * + * @member {boolean} * @private */ this.dirty = true; /** - * Used to detect if the webgl graphics object has changed. If this is set to true then the graphics object will be recalculated. - * - * @property webGLDirty - * @type Boolean + * Used to detect if the WebGL graphics object has changed. If this is set to true then the + * graphics object will be recalculated. + * + * @member {boolean} * @private */ - this.webGLDirty = false; + this.glDirty = false; /** * Used to detect if the cached sprite object needs to be updated. - * - * @property cachedSpriteDirty - * @type Boolean + * + * @member {boolean} * @private */ this.cachedSpriteDirty = false; @@ -133,70 +133,65 @@ }; // constructor -PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Graphics.prototype.constructor = PIXI.Graphics; +Graphics.prototype = Object.create(DisplayObjectContainer.prototype); +Graphics.prototype.constructor = Graphics; +module.exports = Graphics; -/** - * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. - * This is useful if your graphics element does not change often, as it will speed up the rendering of the object in exchange for taking up texture memory. - * It is also useful if you need the graphics object to be anti-aliased, because it will be rendered using canvas. - * This is not recommended if you are constantly redrawing the graphics element. - * - * @property cacheAsBitmap - * @type Boolean - * @default false - * @private - */ -Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { - get: function() { - return this._cacheAsBitmap; - }, - set: function(value) { - this._cacheAsBitmap = value; +Object.defineProperties(Graphics.prototype, { + /** + * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. + * This is useful if your graphics element does not change often, as it will speed up the rendering + * of the object in exchange for taking up texture memory. It is also useful if you need the graphics + * object to be anti-aliased, because it will be rendered using canvas. This is not recommended if + * you are constantly redrawing the graphics element. + * + * @member {boolean} + * @memberof Graphics# + * @default false + * @private + */ + cacheAsBitmap: { + get: function () { + return this._cacheAsBitmap; + }, + set: function (value) { + this._cacheAsBitmap = value; - if(this._cacheAsBitmap) - { - - this._generateCachedSprite(); + if (this._cacheAsBitmap) { + this._generateCachedSprite(); + } + else { + this.destroyCachedSprite(); + this.dirty = true; + } } - else - { - this.destroyCachedSprite(); - this.dirty = true; - } - } }); /** * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. * - * @method lineStyle - * @param lineWidth {Number} width of the line to draw, will update the objects stored style - * @param color {Number} color of the line to draw, will update the objects stored style - * @param alpha {Number} alpha of the line to draw, will update the objects stored style + * @param lineWidth {number} width of the line to draw, will update the objects stored style + * @param color {number} color of the line to draw, will update the objects stored style + * @param alpha {number} alpha of the line to draw, will update the objects stored style * @return {Graphics} */ -PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) -{ +Graphics.prototype.lineStyle = function (lineWidth, color, alpha) { this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - if(this.currentPath) - { - if(this.currentPath.shape.points.length) - { + 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.drawShape( new Polygon( this.currentPath.shape.points.slice(-2) )); } - - // 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; - + else { + // 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; @@ -205,14 +200,12 @@ /** * Moves the current drawing position to x, y. * - * @method moveTo - * @param x {Number} the X coordinate to move to - * @param y {Number} the Y coordinate to move to + * @param x {number} the X coordinate to move to + * @param y {number} the Y coordinate to move to * @return {Graphics} */ -PIXI.Graphics.prototype.moveTo = function(x, y) -{ - this.drawShape(new PIXI.Polygon([x,y])); +Graphics.prototype.moveTo = function (x, y) { + this.drawShape(new Polygon([x,y])); return this; }; @@ -221,13 +214,11 @@ * 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 + * @param x {number} the X coordinate to draw to + * @param y {number} the Y coordinate to draw to * @return {Graphics} */ -PIXI.Graphics.prototype.lineTo = function(x, y) -{ +Graphics.prototype.lineTo = function (x, y) { this.currentPath.shape.points.push(x, y); this.dirty = true; @@ -238,37 +229,36 @@ * Calculate the points for a quadratic bezier curve and then draws it. * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c * - * @method quadraticCurveTo - * @param cpX {Number} Control point x - * @param cpY {Number} Control point y - * @param toX {Number} Destination point x - * @param toY {Number} Destination point y + * @param cpX {number} Control point x + * @param cpY {number} Control point y + * @param toX {number} Destination point x + * @param toY {number} Destination point y * @return {Graphics} */ -PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; +Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { + this.currentPath.shape.points = [0, 0]; + } } - else - { + else { this.moveTo(0,0); } var xa, - ya, - n = 20, - points = this.currentPath.shape.points; - if(points.length === 0)this.moveTo(0, 0); - + ya, + n = 20, + points = this.currentPath.shape.points; + + if (points.length === 0) { + this.moveTo(0, 0); + } var fromX = points[points.length-2]; var fromY = points[points.length-1]; var j = 0; - for (var i = 1; i <= n; i++ ) - { + for (var i = 1; i <= n; ++i) { j = i / n; xa = fromX + ( (cpX - fromX) * j ); @@ -278,7 +268,6 @@ ya + ( ((cpY + ( (toY - cpY) * j )) - ya) * j ) ); } - this.dirty = true; return this; @@ -287,41 +276,38 @@ /** * Calculate the points for a bezier curve and then draws it. * - * @method bezierCurveTo - * @param cpX {Number} Control point x - * @param cpY {Number} Control point y - * @param cpX2 {Number} Second Control point x - * @param cpY2 {Number} Second Control point y - * @param toX {Number} Destination point x - * @param toY {Number} Destination point y + * @param cpX {number} Control point x + * @param cpY {number} Control point y + * @param cpX2 {number} Second Control point x + * @param cpY2 {number} Second Control point y + * @param toX {number} Destination point x + * @param toY {number} Destination point y * @return {Graphics} */ -PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; +Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { + this.currentPath.shape.points = [0, 0]; + } } - else - { + else { this.moveTo(0,0); } var n = 20, - dt, - dt2, - dt3, - t2, - t3, - points = this.currentPath.shape.points; + dt, + dt2, + dt3, + t2, + t3, + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; - + var j = 0; - for (var i=1; i<=n; i++) - { + for (var i = 1; i <= n; ++i) { j = i / n; dt = (1 - j); @@ -330,78 +316,68 @@ t2 = j * j; t3 = t2 * j; - + points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY); } - + this.dirty = true; return this; }; -/* +/** * The arcTo() method creates an arc/curve between two tangents on the canvas. - * + * * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google! * - * @method arcTo - * @param x1 {Number} The x-coordinate of the beginning of the arc - * @param y1 {Number} The y-coordinate of the beginning of the arc - * @param x2 {Number} The x-coordinate of the end of the arc - * @param y2 {Number} The y-coordinate of the end of the arc - * @param radius {Number} The radius of the arc + * @param x1 {number} The x-coordinate of the beginning of the arc + * @param y1 {number} The y-coordinate of the beginning of the arc + * @param x2 {number} The x-coordinate of the end of the arc + * @param y2 {number} The y-coordinate of the end of the arc + * @param radius {number} The radius of the arc * @return {Graphics} */ -PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0) - { +Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { this.currentPath.shape.points.push(x1, y1); } } - else - { + else { this.moveTo(x1, y1); } - var points = this.currentPath.shape.points; - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - var a1 = fromY - y1; - var b1 = fromX - x1; - var a2 = y2 - y1; - var b2 = x2 - x1; - var mm = Math.abs(a1 * b2 - b1 * a2); + var points = this.currentPath.shape.points, + fromX = points[points.length-2], + fromY = points[points.length-1], + a1 = fromY - y1, + b1 = fromX - x1, + a2 = y2 - y1, + b2 = x2 - x1, + mm = Math.abs(a1 * b2 - b1 * a2); - - if (mm < 1.0e-8 || radius === 0) - { - if( points[points.length-2] !== x1 || points[points.length-1] !== y1) - { - //console.log(">>") + if (mm < 1.0e-8 || radius === 0) { + if (points[points.length-2] !== x1 || points[points.length-1] !== y1) { points.push(x1, y1); } } - else - { - var dd = a1 * a1 + b1 * b1; - var cc = a2 * a2 + b2 * b2; - var tt = a1 * a2 + b1 * b2; - var k1 = radius * Math.sqrt(dd) / mm; - var k2 = radius * Math.sqrt(cc) / mm; - var j1 = k1 * tt / dd; - var j2 = k2 * tt / cc; - var cx = k1 * b2 + k2 * b1; - var cy = k1 * a2 + k2 * a1; - var px = b1 * (k2 + j1); - var py = a1 * (k2 + j1); - var qx = b2 * (k1 + j2); - var qy = a2 * (k1 + j2); - var startAngle = Math.atan2(py - cy, px - cx); - var endAngle = Math.atan2(qy - cy, qx - cx); + else { + var dd = a1 * a1 + b1 * b1, + cc = a2 * a2 + b2 * b2, + tt = a1 * a2 + b1 * b2, + k1 = radius * Math.sqrt(dd) / mm, + k2 = radius * Math.sqrt(cc) / mm, + j1 = k1 * tt / dd, + j2 = k2 * tt / cc, + cx = k1 * b2 + k2 * b1, + cy = k1 * a2 + k2 * a1, + px = b1 * (k2 + j1), + py = a1 * (k2 + j1), + qx = b2 * (k1 + j2), + qy = a2 * (k1 + j2), + startAngle = Math.atan2(py - cy, px - cx), + endAngle = Math.atan2(qy - cy, qx - cx); this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1); } @@ -414,71 +390,64 @@ /** * The arc method creates an arc/curve (used to create circles, or parts of circles). * - * @method arc - * @param cx {Number} The x-coordinate of the center of the circle - * @param cy {Number} The y-coordinate of the center of the circle - * @param radius {Number} The radius of the circle - * @param startAngle {Number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) - * @param endAngle {Number} The ending angle, in radians - * @param anticlockwise {Boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. + * @param cx {number} The x-coordinate of the center of the circle + * @param cy {number} The y-coordinate of the center of the circle + * @param radius {number} The radius of the circle + * @param startAngle {number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) + * @param endAngle {number} The ending angle, in radians + * @param anticlockwise {boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. * @return {Graphics} */ -PIXI.Graphics.prototype.arc = function(cx, cy, radius, startAngle, endAngle, anticlockwise) -{ +Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise) { var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; var points; - if( this.currentPath ) - { + if (this.currentPath) { points = this.currentPath.shape.points; - if(points.length === 0) - { + if (points.length === 0) { points.push(startX, startY); } - else if( points[points.length-2] !== startX || points[points.length-1] !== startY) - { + else if (points[points.length-2] !== startX || points[points.length-1] !== startY) { points.push(startX, startY); } } - else - { + else { this.moveTo(startX, startY); points = this.currentPath.shape.points; } - - if (startAngle === endAngle)return this; - if( !anticlockwise && endAngle <= startAngle ) - { + if (startAngle === endAngle) { + return this; + } + + if (!anticlockwise && endAngle <= startAngle) { endAngle += Math.PI * 2; } - else if( anticlockwise && startAngle <= endAngle ) - { + else if (anticlockwise && startAngle <= endAngle) { startAngle += Math.PI * 2; } var sweep = anticlockwise ? (startAngle - endAngle) *-1 : (endAngle - startAngle); - var segs = ( Math.abs(sweep)/ (Math.PI * 2) ) * 40; + var segs = (Math.abs(sweep)/ (Math.PI * 2)) * 40; - if( sweep === 0 ) return this; + if (sweep === 0) { + return this; + } var theta = sweep/(segs*2); var theta2 = theta*2; var cTheta = Math.cos(theta); var sTheta = Math.sin(theta); - + var segMinus = segs - 1; var remainder = ( segMinus % 1 ) / segMinus; - for(var i=0; i<=segMinus; i++) - { + for (var i = 0; i <= segMinus; ++i) { var real = i + remainder * i; - - var angle = ((theta) + startAngle + (theta2 * real)); var c = Math.cos(angle); @@ -497,21 +466,17 @@ * Specifies a simple one-color fill that subsequent calls to other Graphics methods * (such as lineTo() or drawCircle()) use when drawing. * - * @method beginFill - * @param color {Number} the color of the fill - * @param alpha {Number} the alpha of the fill + * @param color {number} the color of the fill + * @param alpha {number} the alpha of the fill * @return {Graphics} */ -PIXI.Graphics.prototype.beginFill = function(color, alpha) -{ +Graphics.prototype.beginFill = function (color, alpha) { this.filling = true; this.fillColor = color || 0; this.fillAlpha = (alpha === undefined) ? 1 : alpha; - if(this.currentPath) - { - if(this.currentPath.shape.points.length <= 2) - { + 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; @@ -523,11 +488,9 @@ /** * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. * - * @method endFill * @return {Graphics} */ -PIXI.Graphics.prototype.endFill = function() -{ +Graphics.prototype.endFill = function () { this.filling = false; this.fillColor = null; this.fillAlpha = 1; @@ -536,33 +499,29 @@ }; /** - * @method drawRect * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle + * @param x {number} The X coord of the top-left of the rectangle + * @param y {number} The Y coord of the top-left of the rectangle + * @param width {number} The width of the rectangle + * @param height {number} The height of the rectangle * @return {Graphics} */ -PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) -{ - this.drawShape(new PIXI.Rectangle(x,y, width, height)); +Graphics.prototype.drawRect = function ( x, y, width, height ) { + this.drawShape(new Rectangle(x,y, width, height)); return this; }; /** - * @method drawRoundedRect * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle - * @param radius {Number} Radius of the rectangle corners + * @param x {number} The X coord of the top-left of the rectangle + * @param y {number} The Y coord of the top-left of the rectangle + * @param width {number} The width of the rectangle + * @param height {number} The height of the rectangle + * @param radius {number} Radius of the rectangle corners */ -PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) -{ - this.drawShape(new PIXI.RoundedRectangle(x, y, width, height, radius)); +Graphics.prototype.drawRoundedRect = function ( x, y, width, height, radius ) { + this.drawShape(new RoundedRectangle(x, y, width, height, radius)); return this; }; @@ -570,15 +529,13 @@ /** * Draws a circle. * - * @method drawCircle - * @param x {Number} The X coordinate of the center of the circle - * @param y {Number} The Y coordinate of the center of the circle - * @param radius {Number} The radius of the circle + * @param x {number} The X coordinate of the center of the circle + * @param y {number} The Y coordinate of the center of the circle + * @param radius {number} The radius of the circle * @return {Graphics} */ -PIXI.Graphics.prototype.drawCircle = function(x, y, radius) -{ - this.drawShape(new PIXI.Circle(x,y, radius)); +Graphics.prototype.drawCircle = function (x, y, radius) { + this.drawShape(new Circle(x,y, radius)); return this; }; @@ -586,16 +543,14 @@ /** * Draws an ellipse. * - * @method drawEllipse - * @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 the ellipse - * @param height {Number} The half height of the ellipse + * @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 the ellipse + * @param height {number} The half height of the ellipse * @return {Graphics} */ -PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) -{ - this.drawShape(new PIXI.Ellipse(x, y, width, height)); +Graphics.prototype.drawEllipse = function (x, y, width, height) { + this.drawShape(new Ellipse(x, y, width, height)); return this; }; @@ -603,25 +558,25 @@ /** * Draws a polygon using the given path. * - * @method drawPolygon * @param path {Array} The path data used to construct the polygon. * @return {Graphics} */ -PIXI.Graphics.prototype.drawPolygon = function(path) -{ - if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); - this.drawShape(new PIXI.Polygon(path)); +Graphics.prototype.drawPolygon = function (path) { + if (!(path instanceof Array)) { + path = Array.prototype.slice.call(arguments); + } + + this.drawShape(new Polygon(path)); + return this; }; /** * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. * - * @method clear * @return {Graphics} */ -PIXI.Graphics.prototype.clear = function() -{ +Graphics.prototype.clear = function () { this.lineWidth = 0; this.filling = false; @@ -636,51 +591,46 @@ * Useful function that returns a texture of the graphics object that can then be used to create sprites * This can be quite useful if your geometry is complicated and needs to be reused multiple times. * - * @method generateTexture - * @param resolution {Number} The resolution of the texture being generated - * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts + * @param resolution {number} The resolution of the texture being generated + * @param scaleMode {number} Should be one of the scaleMode consts * @return {Texture} a texture of the graphics object */ -PIXI.Graphics.prototype.generateTexture = function(resolution, scaleMode) -{ +Graphics.prototype.generateTexture = function (resolution, scaleMode) { resolution = resolution || 1; var bounds = this.getBounds(); - - var canvasBuffer = new PIXI.CanvasBuffer(bounds.width * resolution, bounds.height * resolution); - - var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + + var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + + var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); texture.baseTexture.resolution = resolution; canvasBuffer.context.scale(resolution, resolution); canvasBuffer.context.translate(-bounds.x,-bounds.y); - - PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + CanvasGraphics.renderGraphics(this, canvasBuffer.context); return texture; }; /** -* Renders the object using the WebGL renderer -* -* @method _renderWebGL -* @param renderSession {RenderSession} -* @private -*/ -PIXI.Graphics.prototype._renderWebGL = function(renderSession) -{ + * Renders the object using the WebGL renderer + * + * @method _renderWebGL + * @param renderSession {RenderSession} + * @private + */ +Graphics.prototype._renderWebGL = function (renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element - if(this.visible === false || this.alpha === 0 || this.isMask === true)return; + if (!this.visible || this.alpha <= 0 || this.isMask === true) { + return; + } - if(this._cacheAsBitmap) - { - - if(this.dirty || this.cachedSpriteDirty) - { - + if (this._cacheAsBitmap) { + if (this.dirty || this.cachedSpriteDirty) { this._generateCachedSprite(); - + // we will also need to update the texture on the gpu too! this.updateCachedSpriteTexture(); @@ -689,52 +639,60 @@ } this._cachedSprite.worldAlpha = this.worldAlpha; - PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); return; } - else - { + else { renderSession.spriteBatch.stop(); renderSession.blendModeManager.setBlendMode(this.blendMode); - if(this._mask)renderSession.maskManager.pushMask(this._mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - + if (this._mask) { + renderSession.maskManager.pushMask(this._mask, renderSession); + } + + if (this._filters) { + renderSession.filterManager.pushFilter(this._filterBlock); + } + // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) - { + if (this.blendMode !== renderSession.spriteBatch.currentBlendMode) { renderSession.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + + var blendModeWebGL = blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + renderSession.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); } - + // check if the webgl graphic needs to be updated - if(this.webGLDirty) - { + if (this.glDirty) { this.dirty = true; - this.webGLDirty = false; + this.glDirty = false; } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - + + WebGLGraphics.renderGraphics(this, renderSession); + // only render if it has children! - if(this.children.length) - { + if (this.children.length) { renderSession.spriteBatch.start(); // simple render children! - for(var i=0, j=this.children.length; i maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC) - { + else if (type === Graphics.CIRC) { x = shape.x; y = shape.y; w = shape.radius + lineWidth/2; @@ -939,8 +887,7 @@ minY = y - h < minY ? y - h : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.ELIP) - { + else if (type === Graphics.ELIP) { x = shape.x; y = shape.y; w = shape.width + lineWidth/2; @@ -952,16 +899,14 @@ minY = y - h < minY ? y - h : minY; maxY = y + h > maxY ? y + h : maxY; } - else - { + else { // POLY points = shape.points; - - for (var j = 0; j < points.length; j+=2) - { + for (var j = 0; j < points.length; j += 2) { x = points[j]; y = points[j+1]; + minX = x-lineWidth < minX ? x-lineWidth : minX; maxX = x+lineWidth > maxX ? x+lineWidth : maxX; @@ -971,8 +916,7 @@ } } } - else - { + else { minX = 0; maxX = 0; minY = 0; @@ -980,7 +924,7 @@ } var padding = this.boundsPadding; - + this._localBounds.x = minX - padding; this._localBounds.width = (maxX - minX) + padding * 2; @@ -991,25 +935,21 @@ /** * Generates the cached sprite when the sprite has cacheAsBitmap = true * - * @method _generateCachedSprite * @private */ -PIXI.Graphics.prototype._generateCachedSprite = function() -{ +Graphics.prototype._generateCachedSprite = function () { var bounds = this.getLocalBounds(); - if(!this._cachedSprite) - { - var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); - var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); - - this._cachedSprite = new PIXI.Sprite(texture); + if (!this._cachedSprite) { + var canvasBuffer = new CanvasBuffer(bounds.width, bounds.height); + var texture = Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new Sprite(texture); this._cachedSprite.buffer = canvasBuffer; this._cachedSprite.worldTransform = this.worldTransform; } - else - { + else { this._cachedSprite.buffer.resize(bounds.width, bounds.height); } @@ -1017,25 +957,24 @@ this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); - // this._cachedSprite.buffer.context.save(); + // this._cachedSprite.buffer.context.save(); this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); - - // make sure we set the alpha of the graphics to 1 for the render.. + + // make sure we set the alpha of the graphics to 1 for the render.. this.worldAlpha = 1; // now render the graphic.. - PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + this._cachedSprite.alpha = this.alpha; }; /** * Updates texture size based on canvas size * - * @method updateCachedSpriteTexture * @private */ -PIXI.Graphics.prototype.updateCachedSpriteTexture = function() -{ +Graphics.prototype.updateCachedSpriteTexture = function () { var cachedSprite = this._cachedSprite; var texture = cachedSprite.texture; var canvas = cachedSprite.buffer.canvas; @@ -1055,10 +994,8 @@ /** * Destroys a previous cached sprite. * - * @method destroyCachedSprite */ -PIXI.Graphics.prototype.destroyCachedSprite = function() -{ +Graphics.prototype.destroyCachedSprite = function () { this._cachedSprite.texture.destroy(true); // let the gc collect the unused sprite @@ -1069,26 +1006,22 @@ /** * Draws the given shape to this Graphics object. Can be any of Circle, Rectangle, Ellipse, Line or Polygon. * - * @method drawShape * @param {Circle|Rectangle|Ellipse|Line|Polygon} shape The Shape object to draw. * @return {GraphicsData} The generated GraphicsData object. */ -PIXI.Graphics.prototype.drawShape = function(shape) -{ - if(this.currentPath) - { +Graphics.prototype.drawShape = function (shape) { + if (this.currentPath) { // check current path! - if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + 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); - + var data = new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + this.graphicsData.push(data); - - if(data.type === PIXI.Graphics.POLY) - { + + if (data.type === Graphics.POLY) { data.shape.closed = this.filling; this.currentPath = data; } @@ -1099,37 +1032,39 @@ }; /** - * A GraphicsData object. - * - * @class GraphicsData - * @constructor + * @static + * @constant */ -PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) -{ - this.lineWidth = lineWidth; - this.lineColor = lineColor; - this.lineAlpha = lineAlpha; - this._lineTint = lineColor; +Graphics.POLY = 0; - this.fillColor = fillColor; - this.fillAlpha = fillAlpha; - this._fillTint = fillColor; - this.fill = fill; +/** + * @static + * @constant + */ +Graphics.RECT = 1; - this.shape = shape; - this.type = shape.type; -}; +/** + * @static + * @constant + */ +Graphics.CIRC = 2; -// SOME TYPES: -PIXI.Graphics.POLY = 0; -PIXI.Graphics.RECT = 1; -PIXI.Graphics.CIRC = 2; -PIXI.Graphics.ELIP = 3; -PIXI.Graphics.RREC = 4; +/** + * @static + * @constant + */ +Graphics.ELIP = 3; -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; -PIXI.RoundedRectangle.prototype.type = PIXI.Graphics.RREC; +/** + * @static + * @constant + */ +Graphics.RREC = 4; + +// REFACTOR: Move these to their classes, move types to central location. +Polygon.prototype.type = Graphics.POLY; +Rectangle.prototype.type = Graphics.RECT; +Circle.prototype.type = Graphics.CIRC; +Ellipse.prototype.type = Graphics.ELIP; +RoundedRectangle.prototype.type = Graphics.RREC; diff --git a/README.md b/README.md index 3dbcae4..f11798f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - [x] `filters/` - [x] `geom/` (move to `math/`) - [x] `loaders/` -- [ ] `primitives/` +- [x] `primitives/` - [ ] `renderers/` - [ ] `text/` - [ ] `textures/` diff --git a/src/primitives/Graphics.js b/src/primitives/Graphics.js index 91a44ea..e738d01 100644 --- a/src/primitives/Graphics.js +++ b/src/primitives/Graphics.js @@ -1,41 +1,43 @@ -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - */ +var GraphicsData = require('./GraphicsData'), + Sprite = require('../display/Sprite'), + DisplayObjectContainer = require('../display/DisplayObjectContainer'), + CanvasGraphics = require('../renderers/canvas/CanvasGraphics'), + CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + math = require('../math'); /** - * The Graphics class contains methods used to draw primitive shapes such as lines, circles and rectangles to the display, and color and fill them. - * - * @class Graphics + * The Graphics class contains methods used to draw primitive shapes such as lines, circles and + * rectangles to the display, and color and fill them. + * + * @class * @extends DisplayObjectContainer - * @constructor + * @namespace PIXI */ -PIXI.Graphics = function() -{ - PIXI.DisplayObjectContainer.call( this ); +function Graphics() { + DisplayObjectContainer.call(this); this.renderable = true; /** * The alpha value used when filling the Graphics object. * - * @property fillAlpha - * @type Number + * @member {number} + * @default 1 */ this.fillAlpha = 1; /** * The width (thickness) of any lines drawn. * - * @property lineWidth - * @type Number + * @member {number} + * @default 0 */ this.lineWidth = 0; /** * The color of any lines drawn. * - * @property lineColor - * @type String + * @member {string} * @default 0 */ this.lineColor = 0; @@ -43,8 +45,7 @@ /** * Graphics data * - * @property graphicsData - * @type Array + * @member {object[]} * @private */ this.graphicsData = []; @@ -52,35 +53,31 @@ /** * The tint applied to the graphic shape. This is a hex value. Apply a value of 0xFFFFFF to reset the tint. * - * @property tint - * @type Number + * @member {number} * @default 0xFFFFFF */ this.tint = 0xFFFFFF; /** - * The blend mode to be applied to the graphic shape. Apply a value of PIXI.blendModes.NORMAL to reset the blend mode. + * The blend mode to be applied to the graphic shape. Apply a value of blendModes.NORMAL to reset the blend mode. * - * @property blendMode - * @type Number - * @default PIXI.blendModes.NORMAL; + * @member {number} + * @default blendModes.NORMAL; */ - this.blendMode = PIXI.blendModes.NORMAL; - + this.blendMode = blendModes.NORMAL; + /** * Current path * - * @property currentPath - * @type Object + * @member {object} * @private */ this.currentPath = null; - + /** * Array containing some WebGL-related properties used by the WebGL renderer. * - * @property _webGL - * @type Array + * @member {object[]} * @private */ this._webGL = []; @@ -88,44 +85,47 @@ /** * Whether this shape is being used as a mask. * - * @property isMask - * @type Boolean + * @member {boolean} */ this.isMask = false; /** * The bounds' padding used for bounds calculation. * - * @property boundsPadding - * @type Number + * @member {number} */ this.boundsPadding = 0; - this._localBounds = new PIXI.Rectangle(0,0,1,1); + /** + * A cache of the local bounds to prevent recalculation. + * + * @member {REctangle} + * @private + */ + this._localBounds = new Rectangle(0,0,1,1); /** - * Used to detect if the graphics object has changed. If this is set to true then the graphics object will be recalculated. - * - * @property dirty - * @type Boolean + * Used to detect if the graphics object has changed. If this is set to true then the graphics + * object will be recalculated. + * + * @member {boolean} * @private */ this.dirty = true; /** - * Used to detect if the webgl graphics object has changed. If this is set to true then the graphics object will be recalculated. - * - * @property webGLDirty - * @type Boolean + * Used to detect if the WebGL graphics object has changed. If this is set to true then the + * graphics object will be recalculated. + * + * @member {boolean} * @private */ - this.webGLDirty = false; + this.glDirty = false; /** * Used to detect if the cached sprite object needs to be updated. - * - * @property cachedSpriteDirty - * @type Boolean + * + * @member {boolean} * @private */ this.cachedSpriteDirty = false; @@ -133,70 +133,65 @@ }; // constructor -PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); -PIXI.Graphics.prototype.constructor = PIXI.Graphics; +Graphics.prototype = Object.create(DisplayObjectContainer.prototype); +Graphics.prototype.constructor = Graphics; +module.exports = Graphics; -/** - * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. - * This is useful if your graphics element does not change often, as it will speed up the rendering of the object in exchange for taking up texture memory. - * It is also useful if you need the graphics object to be anti-aliased, because it will be rendered using canvas. - * This is not recommended if you are constantly redrawing the graphics element. - * - * @property cacheAsBitmap - * @type Boolean - * @default false - * @private - */ -Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { - get: function() { - return this._cacheAsBitmap; - }, - set: function(value) { - this._cacheAsBitmap = value; +Object.defineProperties(Graphics.prototype, { + /** + * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. + * This is useful if your graphics element does not change often, as it will speed up the rendering + * of the object in exchange for taking up texture memory. It is also useful if you need the graphics + * object to be anti-aliased, because it will be rendered using canvas. This is not recommended if + * you are constantly redrawing the graphics element. + * + * @member {boolean} + * @memberof Graphics# + * @default false + * @private + */ + cacheAsBitmap: { + get: function () { + return this._cacheAsBitmap; + }, + set: function (value) { + this._cacheAsBitmap = value; - if(this._cacheAsBitmap) - { - - this._generateCachedSprite(); + if (this._cacheAsBitmap) { + this._generateCachedSprite(); + } + else { + this.destroyCachedSprite(); + this.dirty = true; + } } - else - { - this.destroyCachedSprite(); - this.dirty = true; - } - } }); /** * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. * - * @method lineStyle - * @param lineWidth {Number} width of the line to draw, will update the objects stored style - * @param color {Number} color of the line to draw, will update the objects stored style - * @param alpha {Number} alpha of the line to draw, will update the objects stored style + * @param lineWidth {number} width of the line to draw, will update the objects stored style + * @param color {number} color of the line to draw, will update the objects stored style + * @param alpha {number} alpha of the line to draw, will update the objects stored style * @return {Graphics} */ -PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) -{ +Graphics.prototype.lineStyle = function (lineWidth, color, alpha) { this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - if(this.currentPath) - { - if(this.currentPath.shape.points.length) - { + 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.drawShape( new Polygon( this.currentPath.shape.points.slice(-2) )); } - - // 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; - + else { + // 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; @@ -205,14 +200,12 @@ /** * Moves the current drawing position to x, y. * - * @method moveTo - * @param x {Number} the X coordinate to move to - * @param y {Number} the Y coordinate to move to + * @param x {number} the X coordinate to move to + * @param y {number} the Y coordinate to move to * @return {Graphics} */ -PIXI.Graphics.prototype.moveTo = function(x, y) -{ - this.drawShape(new PIXI.Polygon([x,y])); +Graphics.prototype.moveTo = function (x, y) { + this.drawShape(new Polygon([x,y])); return this; }; @@ -221,13 +214,11 @@ * 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 + * @param x {number} the X coordinate to draw to + * @param y {number} the Y coordinate to draw to * @return {Graphics} */ -PIXI.Graphics.prototype.lineTo = function(x, y) -{ +Graphics.prototype.lineTo = function (x, y) { this.currentPath.shape.points.push(x, y); this.dirty = true; @@ -238,37 +229,36 @@ * Calculate the points for a quadratic bezier curve and then draws it. * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c * - * @method quadraticCurveTo - * @param cpX {Number} Control point x - * @param cpY {Number} Control point y - * @param toX {Number} Destination point x - * @param toY {Number} Destination point y + * @param cpX {number} Control point x + * @param cpY {number} Control point y + * @param toX {number} Destination point x + * @param toY {number} Destination point y * @return {Graphics} */ -PIXI.Graphics.prototype.quadraticCurveTo = function(cpX, cpY, toX, toY) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; +Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { + this.currentPath.shape.points = [0, 0]; + } } - else - { + else { this.moveTo(0,0); } var xa, - ya, - n = 20, - points = this.currentPath.shape.points; - if(points.length === 0)this.moveTo(0, 0); - + ya, + n = 20, + points = this.currentPath.shape.points; + + if (points.length === 0) { + this.moveTo(0, 0); + } var fromX = points[points.length-2]; var fromY = points[points.length-1]; var j = 0; - for (var i = 1; i <= n; i++ ) - { + for (var i = 1; i <= n; ++i) { j = i / n; xa = fromX + ( (cpX - fromX) * j ); @@ -278,7 +268,6 @@ ya + ( ((cpY + ( (toY - cpY) * j )) - ya) * j ) ); } - this.dirty = true; return this; @@ -287,41 +276,38 @@ /** * Calculate the points for a bezier curve and then draws it. * - * @method bezierCurveTo - * @param cpX {Number} Control point x - * @param cpY {Number} Control point y - * @param cpX2 {Number} Second Control point x - * @param cpY2 {Number} Second Control point y - * @param toX {Number} Destination point x - * @param toY {Number} Destination point y + * @param cpX {number} Control point x + * @param cpY {number} Control point y + * @param cpX2 {number} Second Control point x + * @param cpY2 {number} Second Control point y + * @param toX {number} Destination point x + * @param toY {number} Destination point y * @return {Graphics} */ -PIXI.Graphics.prototype.bezierCurveTo = function(cpX, cpY, cpX2, cpY2, toX, toY) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0)this.currentPath.shape.points = [0,0]; +Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { + this.currentPath.shape.points = [0, 0]; + } } - else - { + else { this.moveTo(0,0); } var n = 20, - dt, - dt2, - dt3, - t2, - t3, - points = this.currentPath.shape.points; + dt, + dt2, + dt3, + t2, + t3, + points = this.currentPath.shape.points; var fromX = points[points.length-2]; var fromY = points[points.length-1]; - + var j = 0; - for (var i=1; i<=n; i++) - { + for (var i = 1; i <= n; ++i) { j = i / n; dt = (1 - j); @@ -330,78 +316,68 @@ t2 = j * j; t3 = t2 * j; - + points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY); } - + this.dirty = true; return this; }; -/* +/** * The arcTo() method creates an arc/curve between two tangents on the canvas. - * + * * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google! * - * @method arcTo - * @param x1 {Number} The x-coordinate of the beginning of the arc - * @param y1 {Number} The y-coordinate of the beginning of the arc - * @param x2 {Number} The x-coordinate of the end of the arc - * @param y2 {Number} The y-coordinate of the end of the arc - * @param radius {Number} The radius of the arc + * @param x1 {number} The x-coordinate of the beginning of the arc + * @param y1 {number} The y-coordinate of the beginning of the arc + * @param x2 {number} The x-coordinate of the end of the arc + * @param y2 {number} The y-coordinate of the end of the arc + * @param radius {number} The radius of the arc * @return {Graphics} */ -PIXI.Graphics.prototype.arcTo = function(x1, y1, x2, y2, radius) -{ - if( this.currentPath ) - { - if(this.currentPath.shape.points.length === 0) - { +Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) { + if (this.currentPath) { + if (this.currentPath.shape.points.length === 0) { this.currentPath.shape.points.push(x1, y1); } } - else - { + else { this.moveTo(x1, y1); } - var points = this.currentPath.shape.points; - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - var a1 = fromY - y1; - var b1 = fromX - x1; - var a2 = y2 - y1; - var b2 = x2 - x1; - var mm = Math.abs(a1 * b2 - b1 * a2); + var points = this.currentPath.shape.points, + fromX = points[points.length-2], + fromY = points[points.length-1], + a1 = fromY - y1, + b1 = fromX - x1, + a2 = y2 - y1, + b2 = x2 - x1, + mm = Math.abs(a1 * b2 - b1 * a2); - - if (mm < 1.0e-8 || radius === 0) - { - if( points[points.length-2] !== x1 || points[points.length-1] !== y1) - { - //console.log(">>") + if (mm < 1.0e-8 || radius === 0) { + if (points[points.length-2] !== x1 || points[points.length-1] !== y1) { points.push(x1, y1); } } - else - { - var dd = a1 * a1 + b1 * b1; - var cc = a2 * a2 + b2 * b2; - var tt = a1 * a2 + b1 * b2; - var k1 = radius * Math.sqrt(dd) / mm; - var k2 = radius * Math.sqrt(cc) / mm; - var j1 = k1 * tt / dd; - var j2 = k2 * tt / cc; - var cx = k1 * b2 + k2 * b1; - var cy = k1 * a2 + k2 * a1; - var px = b1 * (k2 + j1); - var py = a1 * (k2 + j1); - var qx = b2 * (k1 + j2); - var qy = a2 * (k1 + j2); - var startAngle = Math.atan2(py - cy, px - cx); - var endAngle = Math.atan2(qy - cy, qx - cx); + else { + var dd = a1 * a1 + b1 * b1, + cc = a2 * a2 + b2 * b2, + tt = a1 * a2 + b1 * b2, + k1 = radius * Math.sqrt(dd) / mm, + k2 = radius * Math.sqrt(cc) / mm, + j1 = k1 * tt / dd, + j2 = k2 * tt / cc, + cx = k1 * b2 + k2 * b1, + cy = k1 * a2 + k2 * a1, + px = b1 * (k2 + j1), + py = a1 * (k2 + j1), + qx = b2 * (k1 + j2), + qy = a2 * (k1 + j2), + startAngle = Math.atan2(py - cy, px - cx), + endAngle = Math.atan2(qy - cy, qx - cx); this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1); } @@ -414,71 +390,64 @@ /** * The arc method creates an arc/curve (used to create circles, or parts of circles). * - * @method arc - * @param cx {Number} The x-coordinate of the center of the circle - * @param cy {Number} The y-coordinate of the center of the circle - * @param radius {Number} The radius of the circle - * @param startAngle {Number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) - * @param endAngle {Number} The ending angle, in radians - * @param anticlockwise {Boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. + * @param cx {number} The x-coordinate of the center of the circle + * @param cy {number} The y-coordinate of the center of the circle + * @param radius {number} The radius of the circle + * @param startAngle {number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) + * @param endAngle {number} The ending angle, in radians + * @param anticlockwise {boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. * @return {Graphics} */ -PIXI.Graphics.prototype.arc = function(cx, cy, radius, startAngle, endAngle, anticlockwise) -{ +Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise) { var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; var points; - if( this.currentPath ) - { + if (this.currentPath) { points = this.currentPath.shape.points; - if(points.length === 0) - { + if (points.length === 0) { points.push(startX, startY); } - else if( points[points.length-2] !== startX || points[points.length-1] !== startY) - { + else if (points[points.length-2] !== startX || points[points.length-1] !== startY) { points.push(startX, startY); } } - else - { + else { this.moveTo(startX, startY); points = this.currentPath.shape.points; } - - if (startAngle === endAngle)return this; - if( !anticlockwise && endAngle <= startAngle ) - { + if (startAngle === endAngle) { + return this; + } + + if (!anticlockwise && endAngle <= startAngle) { endAngle += Math.PI * 2; } - else if( anticlockwise && startAngle <= endAngle ) - { + else if (anticlockwise && startAngle <= endAngle) { startAngle += Math.PI * 2; } var sweep = anticlockwise ? (startAngle - endAngle) *-1 : (endAngle - startAngle); - var segs = ( Math.abs(sweep)/ (Math.PI * 2) ) * 40; + var segs = (Math.abs(sweep)/ (Math.PI * 2)) * 40; - if( sweep === 0 ) return this; + if (sweep === 0) { + return this; + } var theta = sweep/(segs*2); var theta2 = theta*2; var cTheta = Math.cos(theta); var sTheta = Math.sin(theta); - + var segMinus = segs - 1; var remainder = ( segMinus % 1 ) / segMinus; - for(var i=0; i<=segMinus; i++) - { + for (var i = 0; i <= segMinus; ++i) { var real = i + remainder * i; - - var angle = ((theta) + startAngle + (theta2 * real)); var c = Math.cos(angle); @@ -497,21 +466,17 @@ * Specifies a simple one-color fill that subsequent calls to other Graphics methods * (such as lineTo() or drawCircle()) use when drawing. * - * @method beginFill - * @param color {Number} the color of the fill - * @param alpha {Number} the alpha of the fill + * @param color {number} the color of the fill + * @param alpha {number} the alpha of the fill * @return {Graphics} */ -PIXI.Graphics.prototype.beginFill = function(color, alpha) -{ +Graphics.prototype.beginFill = function (color, alpha) { this.filling = true; this.fillColor = color || 0; this.fillAlpha = (alpha === undefined) ? 1 : alpha; - if(this.currentPath) - { - if(this.currentPath.shape.points.length <= 2) - { + 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; @@ -523,11 +488,9 @@ /** * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. * - * @method endFill * @return {Graphics} */ -PIXI.Graphics.prototype.endFill = function() -{ +Graphics.prototype.endFill = function () { this.filling = false; this.fillColor = null; this.fillAlpha = 1; @@ -536,33 +499,29 @@ }; /** - * @method drawRect * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle + * @param x {number} The X coord of the top-left of the rectangle + * @param y {number} The Y coord of the top-left of the rectangle + * @param width {number} The width of the rectangle + * @param height {number} The height of the rectangle * @return {Graphics} */ -PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) -{ - this.drawShape(new PIXI.Rectangle(x,y, width, height)); +Graphics.prototype.drawRect = function ( x, y, width, height ) { + this.drawShape(new Rectangle(x,y, width, height)); return this; }; /** - * @method drawRoundedRect * - * @param x {Number} The X coord of the top-left of the rectangle - * @param y {Number} The Y coord of the top-left of the rectangle - * @param width {Number} The width of the rectangle - * @param height {Number} The height of the rectangle - * @param radius {Number} Radius of the rectangle corners + * @param x {number} The X coord of the top-left of the rectangle + * @param y {number} The Y coord of the top-left of the rectangle + * @param width {number} The width of the rectangle + * @param height {number} The height of the rectangle + * @param radius {number} Radius of the rectangle corners */ -PIXI.Graphics.prototype.drawRoundedRect = function( x, y, width, height, radius ) -{ - this.drawShape(new PIXI.RoundedRectangle(x, y, width, height, radius)); +Graphics.prototype.drawRoundedRect = function ( x, y, width, height, radius ) { + this.drawShape(new RoundedRectangle(x, y, width, height, radius)); return this; }; @@ -570,15 +529,13 @@ /** * Draws a circle. * - * @method drawCircle - * @param x {Number} The X coordinate of the center of the circle - * @param y {Number} The Y coordinate of the center of the circle - * @param radius {Number} The radius of the circle + * @param x {number} The X coordinate of the center of the circle + * @param y {number} The Y coordinate of the center of the circle + * @param radius {number} The radius of the circle * @return {Graphics} */ -PIXI.Graphics.prototype.drawCircle = function(x, y, radius) -{ - this.drawShape(new PIXI.Circle(x,y, radius)); +Graphics.prototype.drawCircle = function (x, y, radius) { + this.drawShape(new Circle(x,y, radius)); return this; }; @@ -586,16 +543,14 @@ /** * Draws an ellipse. * - * @method drawEllipse - * @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 the ellipse - * @param height {Number} The half height of the ellipse + * @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 the ellipse + * @param height {number} The half height of the ellipse * @return {Graphics} */ -PIXI.Graphics.prototype.drawEllipse = function(x, y, width, height) -{ - this.drawShape(new PIXI.Ellipse(x, y, width, height)); +Graphics.prototype.drawEllipse = function (x, y, width, height) { + this.drawShape(new Ellipse(x, y, width, height)); return this; }; @@ -603,25 +558,25 @@ /** * Draws a polygon using the given path. * - * @method drawPolygon * @param path {Array} The path data used to construct the polygon. * @return {Graphics} */ -PIXI.Graphics.prototype.drawPolygon = function(path) -{ - if(!(path instanceof Array))path = Array.prototype.slice.call(arguments); - this.drawShape(new PIXI.Polygon(path)); +Graphics.prototype.drawPolygon = function (path) { + if (!(path instanceof Array)) { + path = Array.prototype.slice.call(arguments); + } + + this.drawShape(new Polygon(path)); + return this; }; /** * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. * - * @method clear * @return {Graphics} */ -PIXI.Graphics.prototype.clear = function() -{ +Graphics.prototype.clear = function () { this.lineWidth = 0; this.filling = false; @@ -636,51 +591,46 @@ * Useful function that returns a texture of the graphics object that can then be used to create sprites * This can be quite useful if your geometry is complicated and needs to be reused multiple times. * - * @method generateTexture - * @param resolution {Number} The resolution of the texture being generated - * @param scaleMode {Number} Should be one of the PIXI.scaleMode consts + * @param resolution {number} The resolution of the texture being generated + * @param scaleMode {number} Should be one of the scaleMode consts * @return {Texture} a texture of the graphics object */ -PIXI.Graphics.prototype.generateTexture = function(resolution, scaleMode) -{ +Graphics.prototype.generateTexture = function (resolution, scaleMode) { resolution = resolution || 1; var bounds = this.getBounds(); - - var canvasBuffer = new PIXI.CanvasBuffer(bounds.width * resolution, bounds.height * resolution); - - var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + + var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + + var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); texture.baseTexture.resolution = resolution; canvasBuffer.context.scale(resolution, resolution); canvasBuffer.context.translate(-bounds.x,-bounds.y); - - PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + CanvasGraphics.renderGraphics(this, canvasBuffer.context); return texture; }; /** -* Renders the object using the WebGL renderer -* -* @method _renderWebGL -* @param renderSession {RenderSession} -* @private -*/ -PIXI.Graphics.prototype._renderWebGL = function(renderSession) -{ + * Renders the object using the WebGL renderer + * + * @method _renderWebGL + * @param renderSession {RenderSession} + * @private + */ +Graphics.prototype._renderWebGL = function (renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element - if(this.visible === false || this.alpha === 0 || this.isMask === true)return; + if (!this.visible || this.alpha <= 0 || this.isMask === true) { + return; + } - if(this._cacheAsBitmap) - { - - if(this.dirty || this.cachedSpriteDirty) - { - + if (this._cacheAsBitmap) { + if (this.dirty || this.cachedSpriteDirty) { this._generateCachedSprite(); - + // we will also need to update the texture on the gpu too! this.updateCachedSpriteTexture(); @@ -689,52 +639,60 @@ } this._cachedSprite.worldAlpha = this.worldAlpha; - PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); return; } - else - { + else { renderSession.spriteBatch.stop(); renderSession.blendModeManager.setBlendMode(this.blendMode); - if(this._mask)renderSession.maskManager.pushMask(this._mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - + if (this._mask) { + renderSession.maskManager.pushMask(this._mask, renderSession); + } + + if (this._filters) { + renderSession.filterManager.pushFilter(this._filterBlock); + } + // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) - { + if (this.blendMode !== renderSession.spriteBatch.currentBlendMode) { renderSession.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + + var blendModeWebGL = blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + renderSession.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); } - + // check if the webgl graphic needs to be updated - if(this.webGLDirty) - { + if (this.glDirty) { this.dirty = true; - this.webGLDirty = false; + this.glDirty = false; } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - + + WebGLGraphics.renderGraphics(this, renderSession); + // only render if it has children! - if(this.children.length) - { + if (this.children.length) { renderSession.spriteBatch.start(); // simple render children! - for(var i=0, j=this.children.length; i maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.CIRC) - { + else if (type === Graphics.CIRC) { x = shape.x; y = shape.y; w = shape.radius + lineWidth/2; @@ -939,8 +887,7 @@ minY = y - h < minY ? y - h : minY; maxY = y + h > maxY ? y + h : maxY; } - else if(type === PIXI.Graphics.ELIP) - { + else if (type === Graphics.ELIP) { x = shape.x; y = shape.y; w = shape.width + lineWidth/2; @@ -952,16 +899,14 @@ minY = y - h < minY ? y - h : minY; maxY = y + h > maxY ? y + h : maxY; } - else - { + else { // POLY points = shape.points; - - for (var j = 0; j < points.length; j+=2) - { + for (var j = 0; j < points.length; j += 2) { x = points[j]; y = points[j+1]; + minX = x-lineWidth < minX ? x-lineWidth : minX; maxX = x+lineWidth > maxX ? x+lineWidth : maxX; @@ -971,8 +916,7 @@ } } } - else - { + else { minX = 0; maxX = 0; minY = 0; @@ -980,7 +924,7 @@ } var padding = this.boundsPadding; - + this._localBounds.x = minX - padding; this._localBounds.width = (maxX - minX) + padding * 2; @@ -991,25 +935,21 @@ /** * Generates the cached sprite when the sprite has cacheAsBitmap = true * - * @method _generateCachedSprite * @private */ -PIXI.Graphics.prototype._generateCachedSprite = function() -{ +Graphics.prototype._generateCachedSprite = function () { var bounds = this.getLocalBounds(); - if(!this._cachedSprite) - { - var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); - var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); - - this._cachedSprite = new PIXI.Sprite(texture); + if (!this._cachedSprite) { + var canvasBuffer = new CanvasBuffer(bounds.width, bounds.height); + var texture = Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new Sprite(texture); this._cachedSprite.buffer = canvasBuffer; this._cachedSprite.worldTransform = this.worldTransform; } - else - { + else { this._cachedSprite.buffer.resize(bounds.width, bounds.height); } @@ -1017,25 +957,24 @@ this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); - // this._cachedSprite.buffer.context.save(); + // this._cachedSprite.buffer.context.save(); this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); - - // make sure we set the alpha of the graphics to 1 for the render.. + + // make sure we set the alpha of the graphics to 1 for the render.. this.worldAlpha = 1; // now render the graphic.. - PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + this._cachedSprite.alpha = this.alpha; }; /** * Updates texture size based on canvas size * - * @method updateCachedSpriteTexture * @private */ -PIXI.Graphics.prototype.updateCachedSpriteTexture = function() -{ +Graphics.prototype.updateCachedSpriteTexture = function () { var cachedSprite = this._cachedSprite; var texture = cachedSprite.texture; var canvas = cachedSprite.buffer.canvas; @@ -1055,10 +994,8 @@ /** * Destroys a previous cached sprite. * - * @method destroyCachedSprite */ -PIXI.Graphics.prototype.destroyCachedSprite = function() -{ +Graphics.prototype.destroyCachedSprite = function () { this._cachedSprite.texture.destroy(true); // let the gc collect the unused sprite @@ -1069,26 +1006,22 @@ /** * Draws the given shape to this Graphics object. Can be any of Circle, Rectangle, Ellipse, Line or Polygon. * - * @method drawShape * @param {Circle|Rectangle|Ellipse|Line|Polygon} shape The Shape object to draw. * @return {GraphicsData} The generated GraphicsData object. */ -PIXI.Graphics.prototype.drawShape = function(shape) -{ - if(this.currentPath) - { +Graphics.prototype.drawShape = function (shape) { + if (this.currentPath) { // check current path! - if(this.currentPath.shape.points.length <= 2)this.graphicsData.pop(); + 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); - + var data = new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + this.graphicsData.push(data); - - if(data.type === PIXI.Graphics.POLY) - { + + if (data.type === Graphics.POLY) { data.shape.closed = this.filling; this.currentPath = data; } @@ -1099,37 +1032,39 @@ }; /** - * A GraphicsData object. - * - * @class GraphicsData - * @constructor + * @static + * @constant */ -PIXI.GraphicsData = function(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) -{ - this.lineWidth = lineWidth; - this.lineColor = lineColor; - this.lineAlpha = lineAlpha; - this._lineTint = lineColor; +Graphics.POLY = 0; - this.fillColor = fillColor; - this.fillAlpha = fillAlpha; - this._fillTint = fillColor; - this.fill = fill; +/** + * @static + * @constant + */ +Graphics.RECT = 1; - this.shape = shape; - this.type = shape.type; -}; +/** + * @static + * @constant + */ +Graphics.CIRC = 2; -// SOME TYPES: -PIXI.Graphics.POLY = 0; -PIXI.Graphics.RECT = 1; -PIXI.Graphics.CIRC = 2; -PIXI.Graphics.ELIP = 3; -PIXI.Graphics.RREC = 4; +/** + * @static + * @constant + */ +Graphics.ELIP = 3; -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; -PIXI.RoundedRectangle.prototype.type = PIXI.Graphics.RREC; +/** + * @static + * @constant + */ +Graphics.RREC = 4; + +// REFACTOR: Move these to their classes, move types to central location. +Polygon.prototype.type = Graphics.POLY; +Rectangle.prototype.type = Graphics.RECT; +Circle.prototype.type = Graphics.CIRC; +Ellipse.prototype.type = Graphics.ELIP; +RoundedRectangle.prototype.type = Graphics.RREC; diff --git a/src/primitives/GraphicsData.js b/src/primitives/GraphicsData.js new file mode 100644 index 0000000..c0315ef --- /dev/null +++ b/src/primitives/GraphicsData.js @@ -0,0 +1,23 @@ +/** + * A GraphicsData object. + * + * @class + * @namespace PIXI + */ +function GraphicsData(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) { + this.lineWidth = lineWidth; + this.lineColor = lineColor; + this.lineAlpha = lineAlpha; + this._lineTint = lineColor; + + this.fillColor = fillColor; + this.fillAlpha = fillAlpha; + this._fillTint = fillColor; + this.fill = fill; + + this.shape = shape; + this.type = shape.type; +}; + +GraphicsData.prototype.constructor = GraphicsData; +module.exports = GraphicsData;