diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index b3cf0e8..8632b0e 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1597,6 +1597,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -1613,6 +1614,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -1780,16 +1782,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, @@ -3364,10 +3365,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -3454,6 +3460,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */ @@ -6162,7 +6182,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); @@ -6227,10 +6384,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index b3cf0e8..8632b0e 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1597,6 +1597,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -1613,6 +1614,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -1780,16 +1782,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, @@ -3364,10 +3365,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -3454,6 +3460,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */ @@ -6162,7 +6182,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); @@ -6227,10 +6384,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index ebc1c82..33e59ae 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -144,6 +144,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -160,6 +161,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -327,16 +329,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index b3cf0e8..8632b0e 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1597,6 +1597,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -1613,6 +1614,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -1780,16 +1782,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, @@ -3364,10 +3365,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -3454,6 +3460,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */ @@ -6162,7 +6182,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); @@ -6227,10 +6384,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index ebc1c82..33e59ae 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -144,6 +144,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -160,6 +161,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -327,16 +329,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 7311679..c5577d5 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -20,10 +20,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index b3cf0e8..8632b0e 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1597,6 +1597,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -1613,6 +1614,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -1780,16 +1782,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, @@ -3364,10 +3365,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -3454,6 +3460,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */ @@ -6162,7 +6182,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); @@ -6227,10 +6384,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index ebc1c82..33e59ae 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -144,6 +144,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -160,6 +161,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -327,16 +329,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 7311679..c5577d5 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -20,10 +20,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/renderers/canvas/utils/CanvasTinter.js b/src/pixi/renderers/canvas/utils/CanvasTinter.js index 0ea2db9..d0318fa 100644 --- a/src/pixi/renderers/canvas/utils/CanvasTinter.js +++ b/src/pixi/renderers/canvas/utils/CanvasTinter.js @@ -9,7 +9,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index b3cf0e8..8632b0e 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -1597,6 +1597,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -1613,6 +1614,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -1780,16 +1782,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, @@ -3364,10 +3365,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -3454,6 +3460,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */ @@ -6162,7 +6182,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); @@ -6227,10 +6384,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index ebc1c82..33e59ae 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -144,6 +144,7 @@ this.texture = texture; } + this.cachedTint = 0xFFFFFF; this.updateFrame = true; }; @@ -160,6 +161,7 @@ if(this._width)this.scale.x = this._width / this.texture.frame.width; if(this._height)this.scale.y = this._height / this.texture.frame.height; + this.updateFrame = true; }; @@ -327,16 +329,15 @@ // context[this.smoothProperty] = (this.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR); //} - if(this.tint != 0xFFFFFF) + if(this.tint !== 0xFFFFFF) { if(this.cachedTint !== this.tint) { this.cachedTint = this.tint; - //TODO maybe add some cacheing? - // this.tintedTexture = null; - // create a new tinted texture.. - this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this.texture, this.tint, this.tintedTexture); + //TODO clean up cacheing - how to clean up the caches? + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + } context.drawImage(this.tintedTexture, diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index 7311679..c5577d5 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -20,10 +20,22 @@ if(!PIXI.blendModesCanvas) { PIXI.blendModesCanvas = []; - PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; - PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? - PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; - PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + + if(PIXI.canUseNewCanvasBlendModes()) + { + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "multiply"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "screen"; + } + else + { + // this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough" + PIXI.blendModesCanvas[PIXI.blendModes.NORMAL] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.ADD] = "lighter"; //IS THIS OK??? + PIXI.blendModesCanvas[PIXI.blendModes.MULTIPLY] = "source-over"; + PIXI.blendModesCanvas[PIXI.blendModes.SCREEN] = "source-over"; + } } /** diff --git a/src/pixi/renderers/canvas/utils/CanvasTinter.js b/src/pixi/renderers/canvas/utils/CanvasTinter.js index 0ea2db9..d0318fa 100644 --- a/src/pixi/renderers/canvas/utils/CanvasTinter.js +++ b/src/pixi/renderers/canvas/utils/CanvasTinter.js @@ -9,7 +9,144 @@ /// this.textureCach } -PIXI.CanvasTinter.getTintedTexture = function(texture, color, canvas) +//PIXI.CanvasTinter.cachTint = true; +PIXI.CanvasTinter.cacheStepsPerColorChannel = 8; +PIXI.CanvasTinter.convertTintToImage = false; + +PIXI.CanvasTinter.getTintedTexture = function(sprite, color, canvas) +{ + var cacheMode = 0; + + // + // cach on sprite + // cach on texture + // no cache + + var texture = sprite.texture; + + color = PIXI.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 = PIXI.CanvasTinter.canvas || document.createElement("canvas"); + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-atop'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + if(PIXI.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 refferance to the canvas + PIXI.CanvasTinter.canvas = null; + + } + + return canvas; +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) +{ + var context = canvas.getContext( '2d' ); + + var frame = texture.frame; + + canvas.width = frame.width; + canvas.height = frame.height; + + context.fillStyle = stringColor; + + context.fillRect(0, 0, frame.width, frame.height); + + context.globalCompositeOperation = 'multiply'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + context.globalCompositeOperation = 'destination-in'; + + context.drawImage(texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + 0, + 0, + frame.width, + frame.height); + + + + texture.tintCache[stringColor] = canvas; + + return canvas; +} + +PIXI.CanvasTinter.roundColor = function(color) +{ + var step = PIXI.CanvasTinter.cacheStepsPerColorChannel; + + var rgbValues = PIXI.hex2rgb(color); + + rgbValues[0] = Math.round(rgbValues[0] * step) / step; + rgbValues[1] = Math.round(rgbValues[1] * step) / step; + rgbValues[2] = Math.round(rgbValues[2] * step) / step; + + return PIXI.rgb2hex(rgbValues) +} + +PIXI.CanvasTinter._getTintedTextureFast = function(texture, color, canvas) { var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); diff --git a/src/pixi/utils/Utils.js b/src/pixi/utils/Utils.js index 9b7f8e3..73bfb27 100644 --- a/src/pixi/utils/Utils.js +++ b/src/pixi/utils/Utils.js @@ -48,10 +48,15 @@ * @method hex2rgb * @param hex {Number} */ -PIXI.hex2rgb = function hex2rgb(hex) { +PIXI.hex2rgb = function(hex) { return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; }; + +PIXI.rgb2hex = function(rgb) { + return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); +}; + /** * A polyfill for Function.prototype.bind * @@ -138,6 +143,20 @@ return (Math.floor((r)*255) << 16) | (Math.floor((g)*255) << 8) | (Math.floor((b)*255)); } +PIXI.canUseNewCanvasBlendModes = function() +{ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + context.fillStyle = '#fff'; + context.fillRect(0,0,1,1); + return context.getImageData(0,0,1,1).data[0] === 0; +} + /* * DEBUGGING ONLY */