Added texture caches for canvas tints

This commit is contained in:
Mat Groves 2013-12-29 20:45:59 +00:00
parent 174cc38c2b
commit 5693c682e1
5 changed files with 360 additions and 22 deletions

View file

@ -1597,6 +1597,7 @@ PIXI.Sprite.prototype.setTexture = function(texture)
this.texture = texture;
}
this.cachedTint = 0xFFFFFF;
this.updateFrame = true;
};
@ -1613,6 +1614,7 @@ PIXI.Sprite.prototype.onTextureUpdate = function()
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 @@ PIXI.Sprite.prototype._renderCanvas = function(renderSession)
// 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 @@ window.requestAnimFrame = window.requestAnimationFrame;
* @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 @@ PIXI.unpackColorRGB = function(r, g, b)//r, g, b, a)
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 @@ PIXI.CanvasTinter = function()
/// 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,11 +6384,23 @@ PIXI.CanvasRenderer = function(width, height, view, transparent)
if(!PIXI.blendModesCanvas)
{
PIXI.blendModesCanvas = [];
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";
}
}
/**
* The width of the canvas view

View file

@ -144,6 +144,7 @@ PIXI.Sprite.prototype.setTexture = function(texture)
this.texture = texture;
}
this.cachedTint = 0xFFFFFF;
this.updateFrame = true;
};
@ -160,6 +161,7 @@ PIXI.Sprite.prototype.onTextureUpdate = function()
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 @@ PIXI.Sprite.prototype._renderCanvas = function(renderSession)
// 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,

View file

@ -20,11 +20,23 @@ PIXI.CanvasRenderer = function(width, height, view, transparent)
if(!PIXI.blendModesCanvas)
{
PIXI.blendModesCanvas = [];
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";
}
}
/**
* The width of the canvas view

View file

@ -9,7 +9,144 @@ PIXI.CanvasTinter = function()
/// 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);

View file

@ -48,10 +48,15 @@ window.requestAnimFrame = window.requestAnimationFrame;
* @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 @@ PIXI.unpackColorRGB = function(r, g, b)//r, g, b, a)
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
*/