diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js new file mode 100644 index 0000000..640734d --- /dev/null +++ b/src/core/sprites/canvas/CanvasTinter.js @@ -0,0 +1,238 @@ +var utils = require('../../utils'), +canUseNewCanvasBlendModes = require('../../renderers/canvas/utils/canUseNewCanvasBlendModes'); +/** + * Utility methods for Sprite/Texture tinting. + * @static + * @class + * @memberof PIXI + */ +var CanvasTinter = {}; +module.exports = CanvasTinter; + +/** + * Basically this method just needs a sprite and a color and tints the sprite with the given color. + * + * @param sprite {PIXI.Sprite} the sprite to tint + * @param color {number} the color to use to tint the sprite with + * @return {HTMLCanvasElement} The tinted canvas + */ +CanvasTinter.getTintedTexture = function (sprite, color) +{ + var texture = sprite.texture; + + color = CanvasTinter.roundColor(color); + + var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if (texture.tintCache[stringColor]) + { + return texture.tintCache[stringColor]; + } + + // clone texture.. + var canvas = CanvasTinter.canvas || document.createElement('canvas'); + + //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + CanvasTinter.tintMethod(texture, color, canvas); + + if (CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the reference to the canvas + CanvasTinter.canvas = null; + } + + return canvas; +}; + +/** + * Tint a texture using the 'multiply' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithMultiply = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); +}; + +/** + * Tint a texture using the 'overlay' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithOverlay = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'destination-atop'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + // context.globalCompositeOperation = 'copy'; +}; + +/** + * Tint a texture pixel per pixel. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithPerPixel = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + var rgbValues = utils.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, crop.width, crop.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +/** + * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. + * + * @param color {number} the color to round, should be a hex color + */ +CanvasTinter.roundColor = function (color) +{ + var step = CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = utils.hex2rgb(color); + + rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); + + return utils.rgb2hex(rgbValues); +}; + +/** + * Number of steps which will be used as a cap when rounding colors. + * + * @member + */ +CanvasTinter.cacheStepsPerColorChannel = 8; + +/** + * Tint cache boolean flag. + * + * @member + */ +CanvasTinter.convertTintToImage = false; + +/** + * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. + * + * @member + */ +CanvasTinter.canUseMultiply = canUseNewCanvasBlendModes(); + +/** + * The tinting method that will be used. + * + */ +CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js new file mode 100644 index 0000000..640734d --- /dev/null +++ b/src/core/sprites/canvas/CanvasTinter.js @@ -0,0 +1,238 @@ +var utils = require('../../utils'), +canUseNewCanvasBlendModes = require('../../renderers/canvas/utils/canUseNewCanvasBlendModes'); +/** + * Utility methods for Sprite/Texture tinting. + * @static + * @class + * @memberof PIXI + */ +var CanvasTinter = {}; +module.exports = CanvasTinter; + +/** + * Basically this method just needs a sprite and a color and tints the sprite with the given color. + * + * @param sprite {PIXI.Sprite} the sprite to tint + * @param color {number} the color to use to tint the sprite with + * @return {HTMLCanvasElement} The tinted canvas + */ +CanvasTinter.getTintedTexture = function (sprite, color) +{ + var texture = sprite.texture; + + color = CanvasTinter.roundColor(color); + + var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if (texture.tintCache[stringColor]) + { + return texture.tintCache[stringColor]; + } + + // clone texture.. + var canvas = CanvasTinter.canvas || document.createElement('canvas'); + + //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + CanvasTinter.tintMethod(texture, color, canvas); + + if (CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the reference to the canvas + CanvasTinter.canvas = null; + } + + return canvas; +}; + +/** + * Tint a texture using the 'multiply' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithMultiply = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); +}; + +/** + * Tint a texture using the 'overlay' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithOverlay = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'destination-atop'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + // context.globalCompositeOperation = 'copy'; +}; + +/** + * Tint a texture pixel per pixel. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithPerPixel = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + var rgbValues = utils.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, crop.width, crop.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +/** + * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. + * + * @param color {number} the color to round, should be a hex color + */ +CanvasTinter.roundColor = function (color) +{ + var step = CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = utils.hex2rgb(color); + + rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); + + return utils.rgb2hex(rgbValues); +}; + +/** + * Number of steps which will be used as a cap when rounding colors. + * + * @member + */ +CanvasTinter.cacheStepsPerColorChannel = 8; + +/** + * Tint cache boolean flag. + * + * @member + */ +CanvasTinter.convertTintToImage = false; + +/** + * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. + * + * @member + */ +CanvasTinter.canUseMultiply = canUseNewCanvasBlendModes(); + +/** + * The tinting method that will be used. + * + */ +CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/sprites/renderWebGL.js b/src/core/sprites/renderWebGL.js deleted file mode 100644 index d857e8f..0000000 --- a/src/core/sprites/renderWebGL.js +++ /dev/null @@ -1,23 +0,0 @@ -var = renderWebGL = function (renderer, sprite) -{ - if(this.textureDirty) - { - this.textureDirty = false; - - this._onTextureUpdate(); - - this.vertexDirty = true; - } - - if(this.vertexDirty) - { - this.vertexDirty = false; - - // set the vertex data - this.caclulateVertices(); - - } - - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); -}; diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js new file mode 100644 index 0000000..640734d --- /dev/null +++ b/src/core/sprites/canvas/CanvasTinter.js @@ -0,0 +1,238 @@ +var utils = require('../../utils'), +canUseNewCanvasBlendModes = require('../../renderers/canvas/utils/canUseNewCanvasBlendModes'); +/** + * Utility methods for Sprite/Texture tinting. + * @static + * @class + * @memberof PIXI + */ +var CanvasTinter = {}; +module.exports = CanvasTinter; + +/** + * Basically this method just needs a sprite and a color and tints the sprite with the given color. + * + * @param sprite {PIXI.Sprite} the sprite to tint + * @param color {number} the color to use to tint the sprite with + * @return {HTMLCanvasElement} The tinted canvas + */ +CanvasTinter.getTintedTexture = function (sprite, color) +{ + var texture = sprite.texture; + + color = CanvasTinter.roundColor(color); + + var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if (texture.tintCache[stringColor]) + { + return texture.tintCache[stringColor]; + } + + // clone texture.. + var canvas = CanvasTinter.canvas || document.createElement('canvas'); + + //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + CanvasTinter.tintMethod(texture, color, canvas); + + if (CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the reference to the canvas + CanvasTinter.canvas = null; + } + + return canvas; +}; + +/** + * Tint a texture using the 'multiply' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithMultiply = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); +}; + +/** + * Tint a texture using the 'overlay' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithOverlay = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'destination-atop'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + // context.globalCompositeOperation = 'copy'; +}; + +/** + * Tint a texture pixel per pixel. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithPerPixel = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + var rgbValues = utils.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, crop.width, crop.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +/** + * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. + * + * @param color {number} the color to round, should be a hex color + */ +CanvasTinter.roundColor = function (color) +{ + var step = CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = utils.hex2rgb(color); + + rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); + + return utils.rgb2hex(rgbValues); +}; + +/** + * Number of steps which will be used as a cap when rounding colors. + * + * @member + */ +CanvasTinter.cacheStepsPerColorChannel = 8; + +/** + * Tint cache boolean flag. + * + * @member + */ +CanvasTinter.convertTintToImage = false; + +/** + * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. + * + * @member + */ +CanvasTinter.canUseMultiply = canUseNewCanvasBlendModes(); + +/** + * The tinting method that will be used. + * + */ +CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/sprites/renderWebGL.js b/src/core/sprites/renderWebGL.js deleted file mode 100644 index d857e8f..0000000 --- a/src/core/sprites/renderWebGL.js +++ /dev/null @@ -1,23 +0,0 @@ -var = renderWebGL = function (renderer, sprite) -{ - if(this.textureDirty) - { - this.textureDirty = false; - - this._onTextureUpdate(); - - this.vertexDirty = true; - } - - if(this.vertexDirty) - { - this.vertexDirty = false; - - // set the vertex data - this.caclulateVertices(); - - } - - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); -}; diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js index bde1de4..6d375ea 100644 --- a/src/core/textures/BaseRenderTexture.js +++ b/src/core/textures/BaseRenderTexture.js @@ -2,7 +2,6 @@ Texture = require('./Texture'), RenderTarget = require('../renderers/webgl/utils/RenderTarget'), FilterManager = require('../renderers/webgl/managers/FilterManager'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), math = require('../math'), CONST = require('../const'), tempMatrix = new math.Matrix(), diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js new file mode 100644 index 0000000..640734d --- /dev/null +++ b/src/core/sprites/canvas/CanvasTinter.js @@ -0,0 +1,238 @@ +var utils = require('../../utils'), +canUseNewCanvasBlendModes = require('../../renderers/canvas/utils/canUseNewCanvasBlendModes'); +/** + * Utility methods for Sprite/Texture tinting. + * @static + * @class + * @memberof PIXI + */ +var CanvasTinter = {}; +module.exports = CanvasTinter; + +/** + * Basically this method just needs a sprite and a color and tints the sprite with the given color. + * + * @param sprite {PIXI.Sprite} the sprite to tint + * @param color {number} the color to use to tint the sprite with + * @return {HTMLCanvasElement} The tinted canvas + */ +CanvasTinter.getTintedTexture = function (sprite, color) +{ + var texture = sprite.texture; + + color = CanvasTinter.roundColor(color); + + var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if (texture.tintCache[stringColor]) + { + return texture.tintCache[stringColor]; + } + + // clone texture.. + var canvas = CanvasTinter.canvas || document.createElement('canvas'); + + //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + CanvasTinter.tintMethod(texture, color, canvas); + + if (CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the reference to the canvas + CanvasTinter.canvas = null; + } + + return canvas; +}; + +/** + * Tint a texture using the 'multiply' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithMultiply = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); +}; + +/** + * Tint a texture using the 'overlay' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithOverlay = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'destination-atop'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + // context.globalCompositeOperation = 'copy'; +}; + +/** + * Tint a texture pixel per pixel. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithPerPixel = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + var rgbValues = utils.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, crop.width, crop.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +/** + * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. + * + * @param color {number} the color to round, should be a hex color + */ +CanvasTinter.roundColor = function (color) +{ + var step = CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = utils.hex2rgb(color); + + rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); + + return utils.rgb2hex(rgbValues); +}; + +/** + * Number of steps which will be used as a cap when rounding colors. + * + * @member + */ +CanvasTinter.cacheStepsPerColorChannel = 8; + +/** + * Tint cache boolean flag. + * + * @member + */ +CanvasTinter.convertTintToImage = false; + +/** + * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. + * + * @member + */ +CanvasTinter.canUseMultiply = canUseNewCanvasBlendModes(); + +/** + * The tinting method that will be used. + * + */ +CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/sprites/renderWebGL.js b/src/core/sprites/renderWebGL.js deleted file mode 100644 index d857e8f..0000000 --- a/src/core/sprites/renderWebGL.js +++ /dev/null @@ -1,23 +0,0 @@ -var = renderWebGL = function (renderer, sprite) -{ - if(this.textureDirty) - { - this.textureDirty = false; - - this._onTextureUpdate(); - - this.vertexDirty = true; - } - - if(this.vertexDirty) - { - this.vertexDirty = false; - - // set the vertex data - this.caclulateVertices(); - - } - - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); -}; diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js index bde1de4..6d375ea 100644 --- a/src/core/textures/BaseRenderTexture.js +++ b/src/core/textures/BaseRenderTexture.js @@ -2,7 +2,6 @@ Texture = require('./Texture'), RenderTarget = require('../renderers/webgl/utils/RenderTarget'), FilterManager = require('../renderers/webgl/managers/FilterManager'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), math = require('../math'), CONST = require('../const'), tempMatrix = new math.Matrix(), diff --git a/src/core/utils/index.js b/src/core/utils/index.js index 29cd7fc..241c91a 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -64,40 +64,7 @@ return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); }, - /** - * Checks whether the Canvas BlendModes are supported by the current browser - * - * @return {boolean} whether they are supported - */ - canUseNewCanvasBlendModes: function () - { - if (typeof document === 'undefined') - { - return false; - } - - var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; - var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; - - var magenta = new Image(); - magenta.src = pngHead + 'AP804Oa6' + pngEnd; - - var yellow = new Image(); - yellow.src = pngHead + '/wCKxvRF' + pngEnd; - - var canvas = document.createElement('canvas'); - canvas.width = 6; - canvas.height = 1; - - var context = canvas.getContext('2d'); - context.globalCompositeOperation = 'multiply'; - context.drawImage(magenta, 0, 0); - context.drawImage(yellow, 2, 0); - - var data = context.getImageData(2,0,1,1).data; - - return (data[0] === 255 && data[1] === 0 && data[2] === 0); - }, + /** * Given a number, this function returns the closest number that is a power of two diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 50f33bc..2dd9b06 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -1,7 +1,7 @@ var Container = require('../display/Container'), Texture = require('../textures/Texture'), RenderTexture = require('../textures/RenderTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget = require('../renderers/canvas/utils/CanvasRenderTarget'), GraphicsData = require('./GraphicsData'), Sprite = require('../sprites/Sprite'), math = require('../math'), @@ -689,16 +689,16 @@ var bounds = this.getLocalBounds(); - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); + var canvasRenderTarget = new CanvasRenderTarget(bounds.width * resolution, bounds.height * resolution); - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); + var texture = Texture.fromCanvas(canvasRenderTarget.canvas, scaleMode); texture.baseTexture.resolution = resolution; - canvasBuffer.context.scale(resolution, resolution); + canvasRenderTarget.context.scale(resolution, resolution); - canvasBuffer.context.translate(-bounds.x,-bounds.y); + canvasRenderTarget.context.translate(-bounds.x,-bounds.y); - CanvasGraphics.renderGraphics(this, canvasBuffer.context); + CanvasGraphics.renderGraphics(this, canvasRenderTarget.context); return texture; }; @@ -775,33 +775,6 @@ return; } - // if the tint has changed, set the graphics object to dirty. - if (this._prevTint !== this.tint) { - this.dirty = true; - } - - - var context = renderer.context; - var transform = this.worldTransform; - - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) - { - context.globalCompositeOperation = compositeOperation; - } - - var resolution = renderer.resolution; - - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - renderer.plugins.graphics.render(this); }; diff --git a/src/core/graphics/canvas/CanvasGraphicsRenderer.js b/src/core/graphics/canvas/CanvasGraphicsRenderer.js index 024402d..8a1cb9c 100644 --- a/src/core/graphics/canvas/CanvasGraphicsRenderer.js +++ b/src/core/graphics/canvas/CanvasGraphicsRenderer.js @@ -43,13 +43,32 @@ var renderer = this.renderer; var context = renderer.context; var worldAlpha = graphics.worldAlpha; + var transform = graphics.transform.worldTransform; + var resolution = renderer.resolution; + // if the tint has changed, set the graphics object to dirty. + if (this._prevTint !== this.tint) { + this.dirty = true; + } + + context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + if (graphics.dirty) { this.updateGraphicsTint(graphics); graphics.dirty = false; } + renderer.setBlendMode(graphics.blendMode); + for (var i = 0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; diff --git a/src/core/index.js b/src/core/index.js index 6c064d3..2f885dd 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -44,7 +44,7 @@ // renderers - canvas CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), + CanvasRenderTarget: require('./renderers/canvas/utils/CanvasRenderTarget'), // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js index f4d2ffe..99532b5 100644 --- a/src/core/renderers/canvas/CanvasRenderer.js +++ b/src/core/renderers/canvas/CanvasRenderer.js @@ -1,6 +1,7 @@ var SystemRenderer = require('../SystemRenderer'), CanvasMaskManager = require('./utils/CanvasMaskManager'), CanvasRenderTarget = require('./utils/CanvasRenderTarget'), + mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'), utils = require('../../utils'), math = require('../../math'), CONST = require('../../const'); @@ -83,7 +84,9 @@ this.initPlugins(); - this._mapBlendModes(); + this.blendModes = mapCanvasBlendModesToPixi(); + console.log(this.blendModes) + this._activeBlendMode = null; this.context = null; this.renderingToScreen = false; @@ -97,6 +100,7 @@ module.exports = CanvasRenderer; utils.pluginTarget.mixin(CanvasRenderer); + /** * Renders the object to this canvas view * @@ -114,6 +118,7 @@ if(renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; + if(!renderTexture._canvasRenderTarget) { renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution); @@ -126,6 +131,7 @@ } else { + this.context = this.rootContext; this.resolution = this.rootResolution } @@ -134,18 +140,21 @@ this._lastObjectRendered = displayObject; + + if(!skipUpdateTransform) { // update the scene graph var cacheParent = displayObject.parent; + var tempWt = this._tempDisplayObjectParent.transform.worldTransform; if(transform) { - transform.copy(this._tempDisplayObjectParent.transform.worldTransform); + transform.copy(tempWt); } else { - this._tempDisplayObjectParent.transform.worldTransform.identity(); + tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; @@ -188,6 +197,13 @@ this.emit('postrender'); }; + +CanvasRenderer.prototype.setBlendMode = function (blendMode) +{ + if(this._activeBlendMode === blendMode)return; + renderer.context.globalCompositeOperation = renderer.blendModes[blendMode]; +} + /** * Removes everything from the renderer and optionally removes the Canvas DOM element. * @@ -227,59 +243,4 @@ this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR); } -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () -{ - if (!this.blendModes) - { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) - { - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'screen'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'overlay'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'darken'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'hue'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'saturate'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'color'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; - } - else - { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.BLEND_MODES.NORMAL] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SCREEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.OVERLAY] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DARKEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.HUE] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.SATURATION] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.COLOR] = 'source-over'; - this.blendModes[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; - } - } -}; +}; \ No newline at end of file diff --git a/src/core/renderers/canvas/utils/CanvasTinter.js b/src/core/renderers/canvas/utils/CanvasTinter.js deleted file mode 100644 index 8827558..0000000 --- a/src/core/renderers/canvas/utils/CanvasTinter.js +++ /dev/null @@ -1,238 +0,0 @@ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * @static - * @class - * @memberof PIXI - */ -var CanvasTinter = {}; -module.exports = CanvasTinter; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {PIXI.Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) -{ - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) - { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) - { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else - { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {PIXI.Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) -{ - var context = canvas.getContext( '2d' ); - - var resolution = texture.baseTexture.resolution; - - var crop = texture._frame; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) - { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) -{ - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js new file mode 100644 index 0000000..b2d9b13 --- /dev/null +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -0,0 +1,38 @@ + + +/** + * Checks whether the Canvas BlendModes are supported by the current browser + * + * @return {boolean} whether they are supported + */ +var canUseNewCanvasBlendModes = function () +{ + if (typeof document === 'undefined') + { + return false; + } + + var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; + var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; + + var magenta = new Image(); + magenta.src = pngHead + 'AP804Oa6' + pngEnd; + + var yellow = new Image(); + yellow.src = pngHead + '/wCKxvRF' + pngEnd; + + var canvas = document.createElement('canvas'); + canvas.width = 6; + canvas.height = 1; + + var context = canvas.getContext('2d'); + context.globalCompositeOperation = 'multiply'; + context.drawImage(magenta, 0, 0); + context.drawImage(yellow, 2, 0); + + var data = context.getImageData(2,0,1,1).data; + + return (data[0] === 255 && data[1] === 0 && data[2] === 0); +} + +module.exports = canUseNewCanvasBlendModes; diff --git a/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js new file mode 100644 index 0000000..5a87070 --- /dev/null +++ b/src/core/renderers/canvas/utils/mapCanvasBlendModesToPixi.js @@ -0,0 +1,58 @@ +var CONST = require('../../../Const'), +canUseNewCanvasBlendModes = require('./canUseNewCanvasBlendModes'); + +/** + * Maps gl blend combinations to WebGL + * @class + * @memberof PIXI + */ +function mapWebGLBlendModesToPixi(array) +{ + array = array || []; + + if (canUseNewCanvasBlendModes()) + { + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'multiply'; + array[CONST.BLEND_MODES.SCREEN] = 'screen'; + array[CONST.BLEND_MODES.OVERLAY] = 'overlay'; + array[CONST.BLEND_MODES.DARKEN] = 'darken'; + array[CONST.BLEND_MODES.LIGHTEN] = 'lighten'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'color-dodge'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'color-burn'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'hard-light'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'soft-light'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'difference'; + array[CONST.BLEND_MODES.EXCLUSION] = 'exclusion'; + array[CONST.BLEND_MODES.HUE] = 'hue'; + array[CONST.BLEND_MODES.SATURATION] = 'saturate'; + array[CONST.BLEND_MODES.COLOR] = 'color'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'luminosity'; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' + array[CONST.BLEND_MODES.NORMAL] = 'source-over'; + array[CONST.BLEND_MODES.ADD] = 'lighter'; //IS THIS OK??? + array[CONST.BLEND_MODES.MULTIPLY] = 'source-over'; + array[CONST.BLEND_MODES.SCREEN] = 'source-over'; + array[CONST.BLEND_MODES.OVERLAY] = 'source-over'; + array[CONST.BLEND_MODES.DARKEN] = 'source-over'; + array[CONST.BLEND_MODES.LIGHTEN] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_DODGE] = 'source-over'; + array[CONST.BLEND_MODES.COLOR_BURN] = 'source-over'; + array[CONST.BLEND_MODES.HARD_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.SOFT_LIGHT] = 'source-over'; + array[CONST.BLEND_MODES.DIFFERENCE] = 'source-over'; + array[CONST.BLEND_MODES.EXCLUSION] = 'source-over'; + array[CONST.BLEND_MODES.HUE] = 'source-over'; + array[CONST.BLEND_MODES.SATURATION] = 'source-over'; + array[CONST.BLEND_MODES.COLOR] = 'source-over'; + array[CONST.BLEND_MODES.LUMINOSITY] = 'source-over'; + } + + return array +} + +module.exports = mapWebGLBlendModesToPixi; diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7e65e3e..c96030b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -1,11 +1,9 @@ var math = require('../math'), Texture = require('../textures/Texture'), Container = require('../display/Container'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), tempPoint = new math.Point(), - GroupD8 = math.GroupD8, canvasRenderWorldTransform = new math.Matrix(); /** diff --git a/src/core/sprites/canvas/CanvasSpriteRenderer.js b/src/core/sprites/canvas/CanvasSpriteRenderer.js index c7119bc..4e8a35c 100644 --- a/src/core/sprites/canvas/CanvasSpriteRenderer.js +++ b/src/core/sprites/canvas/CanvasSpriteRenderer.js @@ -1,5 +1,6 @@ var CanvasRenderer = require('../../renderers/canvas/CanvasRenderer'), - CONST = require('../../const') + CONST = require('../../const'), + CanvasTinter = require('./CanvasTinter') /** * @author Mat Groves @@ -52,11 +53,7 @@ return; } - var compositeOperation = renderer.blendModes[this.blendMode]; - if (compositeOperation !== renderer.context.globalCompositeOperation) - { - renderer.context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(sprite.blendMode); // Ignore null sources if (texture.valid) diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js new file mode 100644 index 0000000..640734d --- /dev/null +++ b/src/core/sprites/canvas/CanvasTinter.js @@ -0,0 +1,238 @@ +var utils = require('../../utils'), +canUseNewCanvasBlendModes = require('../../renderers/canvas/utils/canUseNewCanvasBlendModes'); +/** + * Utility methods for Sprite/Texture tinting. + * @static + * @class + * @memberof PIXI + */ +var CanvasTinter = {}; +module.exports = CanvasTinter; + +/** + * Basically this method just needs a sprite and a color and tints the sprite with the given color. + * + * @param sprite {PIXI.Sprite} the sprite to tint + * @param color {number} the color to use to tint the sprite with + * @return {HTMLCanvasElement} The tinted canvas + */ +CanvasTinter.getTintedTexture = function (sprite, color) +{ + var texture = sprite.texture; + + color = CanvasTinter.roundColor(color); + + var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + texture.tintCache = texture.tintCache || {}; + + if (texture.tintCache[stringColor]) + { + return texture.tintCache[stringColor]; + } + + // clone texture.. + var canvas = CanvasTinter.canvas || document.createElement('canvas'); + + //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); + CanvasTinter.tintMethod(texture, color, canvas); + + if (CanvasTinter.convertTintToImage) + { + // is this better? + var tintImage = new Image(); + tintImage.src = canvas.toDataURL(); + + texture.tintCache[stringColor] = tintImage; + } + else + { + texture.tintCache[stringColor] = canvas; + // if we are not converting the texture to an image then we need to lose the reference to the canvas + CanvasTinter.canvas = null; + } + + return canvas; +}; + +/** + * Tint a texture using the 'multiply' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithMultiply = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); +}; + +/** + * Tint a texture using the 'overlay' operation. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithOverlay = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); + context.fillRect(0, 0, crop.width, crop.height); + + context.globalCompositeOperation = 'destination-atop'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + // context.globalCompositeOperation = 'copy'; +}; + +/** + * Tint a texture pixel per pixel. + * + * @param texture {PIXI.Texture} the texture to tint + * @param color {number} the color to use to tint the sprite with + * @param canvas {HTMLCanvasElement} the current canvas + */ +CanvasTinter.tintWithPerPixel = function (texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var resolution = texture.baseTexture.resolution; + + var crop = texture._frame; + + canvas.width = crop.width; + canvas.height = crop.height; + + context.globalCompositeOperation = 'copy'; + context.drawImage( + texture.baseTexture.source, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + crop.width, + crop.height + ); + + var rgbValues = utils.hex2rgb(color); + var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; + + var pixelData = context.getImageData(0, 0, crop.width, crop.height); + + var pixels = pixelData.data; + + for (var i = 0; i < pixels.length; i += 4) + { + pixels[i+0] *= r; + pixels[i+1] *= g; + pixels[i+2] *= b; + } + + context.putImageData(pixelData, 0, 0); +}; + +/** + * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. + * + * @param color {number} the color to round, should be a hex color + */ +CanvasTinter.roundColor = function (color) +{ + var step = CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = utils.hex2rgb(color); + + rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); + rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); + rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); + + return utils.rgb2hex(rgbValues); +}; + +/** + * Number of steps which will be used as a cap when rounding colors. + * + * @member + */ +CanvasTinter.cacheStepsPerColorChannel = 8; + +/** + * Tint cache boolean flag. + * + * @member + */ +CanvasTinter.convertTintToImage = false; + +/** + * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. + * + * @member + */ +CanvasTinter.canUseMultiply = canUseNewCanvasBlendModes(); + +/** + * The tinting method that will be used. + * + */ +CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; diff --git a/src/core/sprites/renderWebGL.js b/src/core/sprites/renderWebGL.js deleted file mode 100644 index d857e8f..0000000 --- a/src/core/sprites/renderWebGL.js +++ /dev/null @@ -1,23 +0,0 @@ -var = renderWebGL = function (renderer, sprite) -{ - if(this.textureDirty) - { - this.textureDirty = false; - - this._onTextureUpdate(); - - this.vertexDirty = true; - } - - if(this.vertexDirty) - { - this.vertexDirty = false; - - // set the vertex data - this.caclulateVertices(); - - } - - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); -}; diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js index bde1de4..6d375ea 100644 --- a/src/core/textures/BaseRenderTexture.js +++ b/src/core/textures/BaseRenderTexture.js @@ -2,7 +2,6 @@ Texture = require('./Texture'), RenderTarget = require('../renderers/webgl/utils/RenderTarget'), FilterManager = require('../renderers/webgl/managers/FilterManager'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), math = require('../math'), CONST = require('../const'), tempMatrix = new math.Matrix(), diff --git a/src/core/utils/index.js b/src/core/utils/index.js index 29cd7fc..241c91a 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -64,40 +64,7 @@ return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); }, - /** - * Checks whether the Canvas BlendModes are supported by the current browser - * - * @return {boolean} whether they are supported - */ - canUseNewCanvasBlendModes: function () - { - if (typeof document === 'undefined') - { - return false; - } - - var pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/'; - var pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=='; - - var magenta = new Image(); - magenta.src = pngHead + 'AP804Oa6' + pngEnd; - - var yellow = new Image(); - yellow.src = pngHead + '/wCKxvRF' + pngEnd; - - var canvas = document.createElement('canvas'); - canvas.width = 6; - canvas.height = 1; - - var context = canvas.getContext('2d'); - context.globalCompositeOperation = 'multiply'; - context.drawImage(magenta, 0, 0); - context.drawImage(yellow, 2, 0); - - var data = context.getImageData(2,0,1,1).data; - - return (data[0] === 255 && data[1] === 0 && data[2] === 0); - }, + /** * Given a number, this function returns the closest number that is a power of two diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js index 82dc55c..295b2b7 100644 --- a/src/extras/cacheAsBitmap.js +++ b/src/extras/cacheAsBitmap.js @@ -209,18 +209,22 @@ var cachedRenderTarget = renderer.context; - var renderTexture = new core.RenderTexture(renderer, bounds.width | 0, bounds.height | 0); + var renderTexture = new core.RenderTexture.create(bounds.width | 0, bounds.height | 0); // need to set // var m = _tempMatrix; + this.transform.worldTransform.copy(m); + m.invert(); - m.tx = -bounds.x; - m.ty = -bounds.y; + m.tx -= bounds.x; + m.ty -= bounds.y; - // set all properties to there original so we can render to a texture + //m.append(this.transform.worldTransform.) + // set all properties to there original so we can render to a texture this.renderCanvas = this._originalRenderCanvas; - renderTexture.render(this, m, true); + //renderTexture.render(this, m, true); + renderer.render(this, renderTexture, true, m, false); // now restore the state be setting the new properties renderer.context = cachedRenderTarget;