diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/renderers/canvas/utils/CanvasBuffer.js b/src/core/renderers/canvas/utils/CanvasBuffer.js deleted file mode 100644 index bb9b4fe..0000000 --- a/src/core/renderers/canvas/utils/CanvasBuffer.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Creates a Canvas element of the given size. - * - * @class - * @memberof PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) -{ - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - width: { - get: function () - { - return this.canvas.width; - }, - set: function (val) - { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - height: { - get: function () - { - return this.canvas.height; - }, - set: function (val) - { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () -{ - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) -{ - this.canvas.width = width; - this.canvas.height = height; -}; - -/** - * Destroys this canvas. - * - */ -CanvasBuffer.prototype.destroy = function () -{ - this.context = null; - this.canvas = null; -}; diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/renderers/canvas/utils/CanvasBuffer.js b/src/core/renderers/canvas/utils/CanvasBuffer.js deleted file mode 100644 index bb9b4fe..0000000 --- a/src/core/renderers/canvas/utils/CanvasBuffer.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Creates a Canvas element of the given size. - * - * @class - * @memberof PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) -{ - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - width: { - get: function () - { - return this.canvas.width; - }, - set: function (val) - { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - height: { - get: function () - { - return this.canvas.height; - }, - set: function (val) - { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () -{ - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) -{ - this.canvas.width = width; - this.canvas.height = height; -}; - -/** - * Destroys this canvas. - * - */ -CanvasBuffer.prototype.destroy = function () -{ - this.context = null; - this.canvas = null; -}; diff --git a/src/core/renderers/canvas/utils/CanvasMaskManager.js b/src/core/renderers/canvas/utils/CanvasMaskManager.js index 48e5397..5246d36 100644 --- a/src/core/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/core/renderers/canvas/utils/CanvasMaskManager.js @@ -1,4 +1,3 @@ -var CanvasGraphics = require('./CanvasGraphics'); /** * A set of functions used to handle masking. @@ -6,8 +5,10 @@ * @class * @memberof PIXI */ -function CanvasMaskManager() -{} +function CanvasMaskManager(renderer) +{ + this.renderer = renderer; +} CanvasMaskManager.prototype.constructor = CanvasMaskManager; module.exports = CanvasMaskManager; @@ -18,13 +19,14 @@ * @param maskData {object} the maskData that will be pushed * @param renderer {PIXI.WebGLRenderer|PIXI.CanvasRenderer} The renderer context to use. */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) +CanvasMaskManager.prototype.pushMask = function (maskData) { + var renderer = this.renderer; renderer.context.save(); var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; + var transform = maskData.transform.worldTransform; var resolution = renderer.resolution; renderer.context.setTransform( @@ -38,15 +40,114 @@ //TODO suport sprite alpha masks?? //lots of effort required. If demand is great enough.. - if(!maskData.texture) + if(!maskData._texture) { - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); + this.renderGraphicsShape(maskData); renderer.context.clip(); } maskData.worldAlpha = cacheAlpha; }; +CanvasMaskManager.prototype.renderGraphicsShape = function (graphics) +{ + var context = this.renderer.context; + var len = graphics.graphicsData.length; + + if (len === 0) + { + return; + } + + context.beginPath(); + + for (var i = 0; i < len; i++) + { + var data = graphics.graphicsData[i]; + var shape = data.shape; + + if (data.type === CONST.SHAPES.POLY) + { + + var points = shape.points; + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) + { + context.closePath(); + } + + } + else if (data.type === CONST.SHAPES.RECT) + { + context.rect(shape.x, shape.y, shape.width, shape.height); + context.closePath(); + } + else if (data.type === CONST.SHAPES.CIRC) + { + // TODO - need to be Undefined! + context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); + context.closePath(); + } + else if (data.type === CONST.SHAPES.ELIP) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var w = shape.width * 2; + var h = shape.height * 2; + + var x = shape.x - w/2; + var y = shape.y - h/2; + + var kappa = 0.5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + else if (data.type === CONST.SHAPES.RREC) + { + + var rx = shape.x; + var ry = shape.y; + var width = shape.width; + var height = shape.height; + var radius = shape.radius; + + var maxRadius = Math.min(width, height) / 2 | 0; + radius = radius > maxRadius ? maxRadius : radius; + + context.moveTo(rx, ry + radius); + context.lineTo(rx, ry + height - radius); + context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); + context.lineTo(rx + width - radius, ry + height); + context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); + context.lineTo(rx + width, ry + radius); + context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); + context.lineTo(rx + radius, ry); + context.quadraticCurveTo(rx, ry, rx, ry + radius); + context.closePath(); + } + } +}; + /** * Restores the current drawing context to the state it was before the mask was applied. * diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/renderers/canvas/utils/CanvasBuffer.js b/src/core/renderers/canvas/utils/CanvasBuffer.js deleted file mode 100644 index bb9b4fe..0000000 --- a/src/core/renderers/canvas/utils/CanvasBuffer.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Creates a Canvas element of the given size. - * - * @class - * @memberof PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) -{ - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - width: { - get: function () - { - return this.canvas.width; - }, - set: function (val) - { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - height: { - get: function () - { - return this.canvas.height; - }, - set: function (val) - { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () -{ - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) -{ - this.canvas.width = width; - this.canvas.height = height; -}; - -/** - * Destroys this canvas. - * - */ -CanvasBuffer.prototype.destroy = function () -{ - this.context = null; - this.canvas = null; -}; diff --git a/src/core/renderers/canvas/utils/CanvasMaskManager.js b/src/core/renderers/canvas/utils/CanvasMaskManager.js index 48e5397..5246d36 100644 --- a/src/core/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/core/renderers/canvas/utils/CanvasMaskManager.js @@ -1,4 +1,3 @@ -var CanvasGraphics = require('./CanvasGraphics'); /** * A set of functions used to handle masking. @@ -6,8 +5,10 @@ * @class * @memberof PIXI */ -function CanvasMaskManager() -{} +function CanvasMaskManager(renderer) +{ + this.renderer = renderer; +} CanvasMaskManager.prototype.constructor = CanvasMaskManager; module.exports = CanvasMaskManager; @@ -18,13 +19,14 @@ * @param maskData {object} the maskData that will be pushed * @param renderer {PIXI.WebGLRenderer|PIXI.CanvasRenderer} The renderer context to use. */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) +CanvasMaskManager.prototype.pushMask = function (maskData) { + var renderer = this.renderer; renderer.context.save(); var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; + var transform = maskData.transform.worldTransform; var resolution = renderer.resolution; renderer.context.setTransform( @@ -38,15 +40,114 @@ //TODO suport sprite alpha masks?? //lots of effort required. If demand is great enough.. - if(!maskData.texture) + if(!maskData._texture) { - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); + this.renderGraphicsShape(maskData); renderer.context.clip(); } maskData.worldAlpha = cacheAlpha; }; +CanvasMaskManager.prototype.renderGraphicsShape = function (graphics) +{ + var context = this.renderer.context; + var len = graphics.graphicsData.length; + + if (len === 0) + { + return; + } + + context.beginPath(); + + for (var i = 0; i < len; i++) + { + var data = graphics.graphicsData[i]; + var shape = data.shape; + + if (data.type === CONST.SHAPES.POLY) + { + + var points = shape.points; + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) + { + context.closePath(); + } + + } + else if (data.type === CONST.SHAPES.RECT) + { + context.rect(shape.x, shape.y, shape.width, shape.height); + context.closePath(); + } + else if (data.type === CONST.SHAPES.CIRC) + { + // TODO - need to be Undefined! + context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); + context.closePath(); + } + else if (data.type === CONST.SHAPES.ELIP) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var w = shape.width * 2; + var h = shape.height * 2; + + var x = shape.x - w/2; + var y = shape.y - h/2; + + var kappa = 0.5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + else if (data.type === CONST.SHAPES.RREC) + { + + var rx = shape.x; + var ry = shape.y; + var width = shape.width; + var height = shape.height; + var radius = shape.radius; + + var maxRadius = Math.min(width, height) / 2 | 0; + radius = radius > maxRadius ? maxRadius : radius; + + context.moveTo(rx, ry + radius); + context.lineTo(rx, ry + height - radius); + context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); + context.lineTo(rx + width - radius, ry + height); + context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); + context.lineTo(rx + width, ry + radius); + context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); + context.lineTo(rx + radius, ry); + context.quadraticCurveTo(rx, ry, rx, ry + radius); + context.closePath(); + } + } +}; + /** * Restores the current drawing context to the state it was before the mask was applied. * diff --git a/src/core/renderers/canvas/utils/CanvasRenderTarget.js b/src/core/renderers/canvas/utils/CanvasRenderTarget.js new file mode 100644 index 0000000..5030080 --- /dev/null +++ b/src/core/renderers/canvas/utils/CanvasRenderTarget.js @@ -0,0 +1,100 @@ +/** + * Creates a Canvas element of the given size. + * + * @class + * @memberof PIXI + * @param width {number} the width for the newly created canvas + * @param height {number} the height for the newly created canvas + */ +function CanvasRenderTarget(width, height, resolution) +{ + /** + * The Canvas object that belongs to this CanvasRenderTarget. + * + * @member {HTMLCanvasElement} + */ + this.canvas = document.createElement('canvas'); + + /** + * A CanvasRenderingContext2D object representing a two-dimensional rendering context. + * + * @member {CanvasRenderingContext2D} + */ + this.context = this.canvas.getContext('2d'); + + this.resolution = resolution; + + this.resize(width, height); +} + +CanvasRenderTarget.prototype.constructor = CanvasRenderTarget; +module.exports = CanvasRenderTarget; + +Object.defineProperties(CanvasRenderTarget.prototype, { + /** + * The width of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + width: { + get: function () + { + return this.canvas.width; + }, + set: function (val) + { + this.canvas.width = val; + } + }, + /** + * The height of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + height: { + get: function () + { + return this.canvas.height; + }, + set: function (val) + { + this.canvas.height = val; + } + } +}); + +/** + * Clears the canvas that was created by the CanvasRenderTarget class. + * + * @private + */ +CanvasRenderTarget.prototype.clear = function () +{ + this.context.setTransform(1, 0, 0, 1, 0, 0); + this.context.clearRect(0,0, this.canvas.width, this.canvas.height); +}; + +/** + * Resizes the canvas to the specified width and height. + * + * @param width {number} the new width of the canvas + * @param height {number} the new height of the canvas + */ +CanvasRenderTarget.prototype.resize = function (width, height) +{ + + this.canvas.width = width * this.resolution; + this.canvas.height = height * this.resolution; +}; + +/** + * Destroys this canvas. + * + */ +CanvasRenderTarget.prototype.destroy = function () +{ + this.context = null; + this.canvas = null; +}; diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/renderers/canvas/utils/CanvasBuffer.js b/src/core/renderers/canvas/utils/CanvasBuffer.js deleted file mode 100644 index bb9b4fe..0000000 --- a/src/core/renderers/canvas/utils/CanvasBuffer.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Creates a Canvas element of the given size. - * - * @class - * @memberof PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) -{ - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - width: { - get: function () - { - return this.canvas.width; - }, - set: function (val) - { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - height: { - get: function () - { - return this.canvas.height; - }, - set: function (val) - { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () -{ - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) -{ - this.canvas.width = width; - this.canvas.height = height; -}; - -/** - * Destroys this canvas. - * - */ -CanvasBuffer.prototype.destroy = function () -{ - this.context = null; - this.canvas = null; -}; diff --git a/src/core/renderers/canvas/utils/CanvasMaskManager.js b/src/core/renderers/canvas/utils/CanvasMaskManager.js index 48e5397..5246d36 100644 --- a/src/core/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/core/renderers/canvas/utils/CanvasMaskManager.js @@ -1,4 +1,3 @@ -var CanvasGraphics = require('./CanvasGraphics'); /** * A set of functions used to handle masking. @@ -6,8 +5,10 @@ * @class * @memberof PIXI */ -function CanvasMaskManager() -{} +function CanvasMaskManager(renderer) +{ + this.renderer = renderer; +} CanvasMaskManager.prototype.constructor = CanvasMaskManager; module.exports = CanvasMaskManager; @@ -18,13 +19,14 @@ * @param maskData {object} the maskData that will be pushed * @param renderer {PIXI.WebGLRenderer|PIXI.CanvasRenderer} The renderer context to use. */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) +CanvasMaskManager.prototype.pushMask = function (maskData) { + var renderer = this.renderer; renderer.context.save(); var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; + var transform = maskData.transform.worldTransform; var resolution = renderer.resolution; renderer.context.setTransform( @@ -38,15 +40,114 @@ //TODO suport sprite alpha masks?? //lots of effort required. If demand is great enough.. - if(!maskData.texture) + if(!maskData._texture) { - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); + this.renderGraphicsShape(maskData); renderer.context.clip(); } maskData.worldAlpha = cacheAlpha; }; +CanvasMaskManager.prototype.renderGraphicsShape = function (graphics) +{ + var context = this.renderer.context; + var len = graphics.graphicsData.length; + + if (len === 0) + { + return; + } + + context.beginPath(); + + for (var i = 0; i < len; i++) + { + var data = graphics.graphicsData[i]; + var shape = data.shape; + + if (data.type === CONST.SHAPES.POLY) + { + + var points = shape.points; + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) + { + context.closePath(); + } + + } + else if (data.type === CONST.SHAPES.RECT) + { + context.rect(shape.x, shape.y, shape.width, shape.height); + context.closePath(); + } + else if (data.type === CONST.SHAPES.CIRC) + { + // TODO - need to be Undefined! + context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); + context.closePath(); + } + else if (data.type === CONST.SHAPES.ELIP) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var w = shape.width * 2; + var h = shape.height * 2; + + var x = shape.x - w/2; + var y = shape.y - h/2; + + var kappa = 0.5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + else if (data.type === CONST.SHAPES.RREC) + { + + var rx = shape.x; + var ry = shape.y; + var width = shape.width; + var height = shape.height; + var radius = shape.radius; + + var maxRadius = Math.min(width, height) / 2 | 0; + radius = radius > maxRadius ? maxRadius : radius; + + context.moveTo(rx, ry + radius); + context.lineTo(rx, ry + height - radius); + context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); + context.lineTo(rx + width - radius, ry + height); + context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); + context.lineTo(rx + width, ry + radius); + context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); + context.lineTo(rx + radius, ry); + context.quadraticCurveTo(rx, ry, rx, ry + radius); + context.closePath(); + } + } +}; + /** * Restores the current drawing context to the state it was before the mask was applied. * diff --git a/src/core/renderers/canvas/utils/CanvasRenderTarget.js b/src/core/renderers/canvas/utils/CanvasRenderTarget.js new file mode 100644 index 0000000..5030080 --- /dev/null +++ b/src/core/renderers/canvas/utils/CanvasRenderTarget.js @@ -0,0 +1,100 @@ +/** + * Creates a Canvas element of the given size. + * + * @class + * @memberof PIXI + * @param width {number} the width for the newly created canvas + * @param height {number} the height for the newly created canvas + */ +function CanvasRenderTarget(width, height, resolution) +{ + /** + * The Canvas object that belongs to this CanvasRenderTarget. + * + * @member {HTMLCanvasElement} + */ + this.canvas = document.createElement('canvas'); + + /** + * A CanvasRenderingContext2D object representing a two-dimensional rendering context. + * + * @member {CanvasRenderingContext2D} + */ + this.context = this.canvas.getContext('2d'); + + this.resolution = resolution; + + this.resize(width, height); +} + +CanvasRenderTarget.prototype.constructor = CanvasRenderTarget; +module.exports = CanvasRenderTarget; + +Object.defineProperties(CanvasRenderTarget.prototype, { + /** + * The width of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + width: { + get: function () + { + return this.canvas.width; + }, + set: function (val) + { + this.canvas.width = val; + } + }, + /** + * The height of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + height: { + get: function () + { + return this.canvas.height; + }, + set: function (val) + { + this.canvas.height = val; + } + } +}); + +/** + * Clears the canvas that was created by the CanvasRenderTarget class. + * + * @private + */ +CanvasRenderTarget.prototype.clear = function () +{ + this.context.setTransform(1, 0, 0, 1, 0, 0); + this.context.clearRect(0,0, this.canvas.width, this.canvas.height); +}; + +/** + * Resizes the canvas to the specified width and height. + * + * @param width {number} the new width of the canvas + * @param height {number} the new height of the canvas + */ +CanvasRenderTarget.prototype.resize = function (width, height) +{ + + this.canvas.width = width * this.resolution; + this.canvas.height = height * this.resolution; +}; + +/** + * Destroys this canvas. + * + */ +CanvasRenderTarget.prototype.destroy = function () +{ + this.context = null; + this.canvas = null; +}; diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index 08854d8..c7119bc 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -146,6 +146,7 @@ } else { + renderer.context.drawImage( texture.baseTexture.source, texture.frame.x * resolution, diff --git a/src/core/index.js b/src/core/index.js index cc4aa4d..6c064d3 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -20,6 +20,7 @@ // sprites Sprite: require('./sprites/Sprite'), + CanvasSpriteRender: require('./sprites/canvas/CanvasSpriteRenderer'), //ParticleContainer: require('./particles/ParticleContainer'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), //ParticleRenderer: require('./particles/webgl/ParticleRenderer'), @@ -31,6 +32,7 @@ Graphics: require('./graphics/Graphics'), GraphicsData: require('./graphics/GraphicsData'), GraphicsRenderer: require('./graphics/webgl/GraphicsRenderer'), + CanvasGraphicsRenderer: require('./graphics/canvas/CanvasGraphicsRenderer'), // textures Texture: require('./textures/Texture'), @@ -42,7 +44,6 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), // renderers - webgl @@ -81,7 +82,7 @@ width = width || 800; height = height || 600; - if (!noWebGL && core.utils.isWebGLSupported()) + if (false)//!noWebGL && core.utils.isWebGLSupported()) { return new core.WebGLRenderer(width, height, options); } diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index 761b22c..f4d2ffe 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,5 +1,6 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), + CanvasRenderTarget = require('./utils/CanvasRenderTarget'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -36,7 +37,8 @@ * * @member {CanvasRenderingContext2D} */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); + this.rootContext = this.view.getContext('2d', { alpha: this.transparent }); + this.rootResolution = this.resolution; /** * Boolean flag controlling canvas refresh. @@ -50,7 +52,7 @@ * * @member {PIXI.CanvasMaskManager} */ - this.maskManager = new CanvasMaskManager(); + this.maskManager = new CanvasMaskManager(this); /** * The canvas property used to set the canvas smoothing property. @@ -59,21 +61,21 @@ */ this.smoothProperty = 'imageSmoothingEnabled'; - if (!this.context.imageSmoothingEnabled) + if (!this.rootContext.imageSmoothingEnabled) { - if (this.context.webkitImageSmoothingEnabled) + if (this.rootContext.webkitImageSmoothingEnabled) { this.smoothProperty = 'webkitImageSmoothingEnabled'; } - else if (this.context.mozImageSmoothingEnabled) + else if (this.rootContext.mozImageSmoothingEnabled) { this.smoothProperty = 'mozImageSmoothingEnabled'; } - else if (this.context.oImageSmoothingEnabled) + else if (this.rootContext.oImageSmoothingEnabled) { this.smoothProperty = 'oImageSmoothingEnabled'; } - else if (this.context.msImageSmoothingEnabled) + else if (this.rootContext.msImageSmoothingEnabled) { this.smoothProperty = 'msImageSmoothingEnabled'; } @@ -83,8 +85,8 @@ this._mapBlendModes(); - - + this.context = null; + this.renderingToScreen = false; this.resize(width, height); } @@ -102,16 +104,50 @@ */ CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform) { - var context = this.context; + // can be handy to know! + this.renderingToScreen = !renderTexture; + + this.emit('prerender'); + if(renderTexture) + { + renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) + { + renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); + renderTexture.source = renderTexture._canvasRenderTarget.canvas; + renderTexture.valid = true; + } + + this.context = renderTexture._canvasRenderTarget.context; + this.resolution = renderTexture._canvasRenderTarget.resolution; + } + else + { + this.context = this.rootContext; + this.resolution = this.rootResolution + } + + var context = this.context; + this._lastObjectRendered = displayObject; if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + + if(transform) + { + transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + } + else + { + this._tempDisplayObjectParent.transform.worldTransform.identity(); + } + displayObject.parent = this._tempDisplayObjectParent; displayObject.updateTransform(); displayObject.parent = cacheParent; @@ -188,7 +224,7 @@ //surely a browser bug?? Let pixi fix that for you.. if(this.smoothProperty) { - this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); + this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } }; diff --git a/src/core/renderers/canvas/utils/CanvasBuffer.js b/src/core/renderers/canvas/utils/CanvasBuffer.js deleted file mode 100644 index bb9b4fe..0000000 --- a/src/core/renderers/canvas/utils/CanvasBuffer.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Creates a Canvas element of the given size. - * - * @class - * @memberof PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) -{ - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - width: { - get: function () - { - return this.canvas.width; - }, - set: function (val) - { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof PIXI.CanvasBuffer# - */ - height: { - get: function () - { - return this.canvas.height; - }, - set: function (val) - { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () -{ - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) -{ - this.canvas.width = width; - this.canvas.height = height; -}; - -/** - * Destroys this canvas. - * - */ -CanvasBuffer.prototype.destroy = function () -{ - this.context = null; - this.canvas = null; -}; diff --git a/src/core/renderers/canvas/utils/CanvasMaskManager.js b/src/core/renderers/canvas/utils/CanvasMaskManager.js index 48e5397..5246d36 100644 --- a/src/core/renderers/canvas/utils/CanvasMaskManager.js +++ b/src/core/renderers/canvas/utils/CanvasMaskManager.js @@ -1,4 +1,3 @@ -var CanvasGraphics = require('./CanvasGraphics'); /** * A set of functions used to handle masking. @@ -6,8 +5,10 @@ * @class * @memberof PIXI */ -function CanvasMaskManager() -{} +function CanvasMaskManager(renderer) +{ + this.renderer = renderer; +} CanvasMaskManager.prototype.constructor = CanvasMaskManager; module.exports = CanvasMaskManager; @@ -18,13 +19,14 @@ * @param maskData {object} the maskData that will be pushed * @param renderer {PIXI.WebGLRenderer|PIXI.CanvasRenderer} The renderer context to use. */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) +CanvasMaskManager.prototype.pushMask = function (maskData) { + var renderer = this.renderer; renderer.context.save(); var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; + var transform = maskData.transform.worldTransform; var resolution = renderer.resolution; renderer.context.setTransform( @@ -38,15 +40,114 @@ //TODO suport sprite alpha masks?? //lots of effort required. If demand is great enough.. - if(!maskData.texture) + if(!maskData._texture) { - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); + this.renderGraphicsShape(maskData); renderer.context.clip(); } maskData.worldAlpha = cacheAlpha; }; +CanvasMaskManager.prototype.renderGraphicsShape = function (graphics) +{ + var context = this.renderer.context; + var len = graphics.graphicsData.length; + + if (len === 0) + { + return; + } + + context.beginPath(); + + for (var i = 0; i < len; i++) + { + var data = graphics.graphicsData[i]; + var shape = data.shape; + + if (data.type === CONST.SHAPES.POLY) + { + + var points = shape.points; + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) + { + context.closePath(); + } + + } + else if (data.type === CONST.SHAPES.RECT) + { + context.rect(shape.x, shape.y, shape.width, shape.height); + context.closePath(); + } + else if (data.type === CONST.SHAPES.CIRC) + { + // TODO - need to be Undefined! + context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); + context.closePath(); + } + else if (data.type === CONST.SHAPES.ELIP) + { + + // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var w = shape.width * 2; + var h = shape.height * 2; + + var x = shape.x - w/2; + var y = shape.y - h/2; + + var kappa = 0.5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + else if (data.type === CONST.SHAPES.RREC) + { + + var rx = shape.x; + var ry = shape.y; + var width = shape.width; + var height = shape.height; + var radius = shape.radius; + + var maxRadius = Math.min(width, height) / 2 | 0; + radius = radius > maxRadius ? maxRadius : radius; + + context.moveTo(rx, ry + radius); + context.lineTo(rx, ry + height - radius); + context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); + context.lineTo(rx + width - radius, ry + height); + context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); + context.lineTo(rx + width, ry + radius); + context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); + context.lineTo(rx + radius, ry); + context.quadraticCurveTo(rx, ry, rx, ry + radius); + context.closePath(); + } + } +}; + /** * Restores the current drawing context to the state it was before the mask was applied. * diff --git a/src/core/renderers/canvas/utils/CanvasRenderTarget.js b/src/core/renderers/canvas/utils/CanvasRenderTarget.js new file mode 100644 index 0000000..5030080 --- /dev/null +++ b/src/core/renderers/canvas/utils/CanvasRenderTarget.js @@ -0,0 +1,100 @@ +/** + * Creates a Canvas element of the given size. + * + * @class + * @memberof PIXI + * @param width {number} the width for the newly created canvas + * @param height {number} the height for the newly created canvas + */ +function CanvasRenderTarget(width, height, resolution) +{ + /** + * The Canvas object that belongs to this CanvasRenderTarget. + * + * @member {HTMLCanvasElement} + */ + this.canvas = document.createElement('canvas'); + + /** + * A CanvasRenderingContext2D object representing a two-dimensional rendering context. + * + * @member {CanvasRenderingContext2D} + */ + this.context = this.canvas.getContext('2d'); + + this.resolution = resolution; + + this.resize(width, height); +} + +CanvasRenderTarget.prototype.constructor = CanvasRenderTarget; +module.exports = CanvasRenderTarget; + +Object.defineProperties(CanvasRenderTarget.prototype, { + /** + * The width of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + width: { + get: function () + { + return this.canvas.width; + }, + set: function (val) + { + this.canvas.width = val; + } + }, + /** + * The height of the canvas buffer in pixels. + * + * @member {number} + * @memberof PIXI.CanvasRenderTarget# + */ + height: { + get: function () + { + return this.canvas.height; + }, + set: function (val) + { + this.canvas.height = val; + } + } +}); + +/** + * Clears the canvas that was created by the CanvasRenderTarget class. + * + * @private + */ +CanvasRenderTarget.prototype.clear = function () +{ + this.context.setTransform(1, 0, 0, 1, 0, 0); + this.context.clearRect(0,0, this.canvas.width, this.canvas.height); +}; + +/** + * Resizes the canvas to the specified width and height. + * + * @param width {number} the new width of the canvas + * @param height {number} the new height of the canvas + */ +CanvasRenderTarget.prototype.resize = function (width, height) +{ + + this.canvas.width = width * this.resolution; + this.canvas.height = height * this.resolution; +}; + +/** + * Destroys this canvas. + * + */ +CanvasRenderTarget.prototype.destroy = function () +{ + this.context = null; + this.canvas = null; +}; diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index 08854d8..c7119bc 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -146,6 +146,7 @@ } else { + renderer.context.drawImage( texture.baseTexture.source, texture.frame.x * resolution, diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js index e61a97b..bde1de4 100644 --- a/src/core/textures/BaseRenderTexture.js +++ b/src/core/textures/BaseRenderTexture.js @@ -68,6 +68,8 @@ this._glRenderTargets = []; + this._canvasRenderTarget = null; + /** * The renderer this BaseRenderTexture uses. A BaseRenderTexture can only belong to one renderer at the moment if its webGL. *