var SystemRenderer = require('../SystemRenderer'),
CanvasMaskManager = require('./utils/CanvasMaskManager'),
utils = require('../../utils'),
math = require('../../math'),
CONST = require('../../const');
/**
* The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
* Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :)
*
* @class
* @memberof PIXI
* @extends PIXI.SystemRenderer
* @param [width=800] {number} the width of the canvas view
* @param [height=600] {number} the height of the canvas view
* @param [options] {object} The optional renderer parameters
* @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional
* @param [options.transparent=false] {boolean} If the render view is transparent, default false
* @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false
* @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment)
* @param [options.resolution=1] {number} the resolution of the renderer retina would be 2
* @param [options.clearBeforeRender=true] {boolean} This sets if the CanvasRenderer will clear the canvas or
* not before the new render pass.
* @param [options.roundPixels=false] {boolean} If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
*/
function CanvasRenderer(width, height, options)
{
options = options || {};
SystemRenderer.call(this, 'Canvas', width, height, options);
this.type = CONST.RENDERER_TYPE.CANVAS;
/**
* The canvas 2d context that everything is drawn with.
*
* @member {CanvasRenderingContext2D}
*/
this.context = this.view.getContext('2d', { alpha: this.transparent });
/**
* Boolean flag controlling canvas refresh.
*
* @member {boolean}
*/
this.refresh = true;
/**
* Instance of a CanvasMaskManager, handles masking when using the canvas renderer.
*
* @member {PIXI.CanvasMaskManager}
*/
this.maskManager = new CanvasMaskManager();
/**
* The canvas property used to set the canvas smoothing property.
*
* @member {string}
*/
this.smoothProperty = 'imageSmoothingEnabled';
if (!this.context.imageSmoothingEnabled)
{
if (this.context.webkitImageSmoothingEnabled)
{
this.smoothProperty = 'webkitImageSmoothingEnabled';
}
else if (this.context.mozImageSmoothingEnabled)
{
this.smoothProperty = 'mozImageSmoothingEnabled';
}
else if (this.context.oImageSmoothingEnabled)
{
this.smoothProperty = 'oImageSmoothingEnabled';
}
else if (this.context.msImageSmoothingEnabled)
{
this.smoothProperty = 'msImageSmoothingEnabled';
}
}
this.initPlugins();
this._mapBlendModes();
/**
* This temporary display object used as the parent of the currently being rendered item
*
* @member {PIXI.DisplayObject}
* @private
*/
this._tempDisplayObjectParent = {
worldTransform: new math.Matrix(),
worldAlpha: 1
};
this.resize(width, height);
}
// constructor
CanvasRenderer.prototype = Object.create(SystemRenderer.prototype);
CanvasRenderer.prototype.constructor = CanvasRenderer;
module.exports = CanvasRenderer;
utils.pluginTarget.mixin(CanvasRenderer);
/**
* Renders the object to this canvas view
*
* @param object {PIXI.DisplayObject} the object to be rendered
*/
CanvasRenderer.prototype.render = function (object)
{
this.emit('prerender');
var cacheParent = object.parent;
this._lastObjectRendered = object;
object.parent = this._tempDisplayObjectParent;
// update the scene graph
object.updateTransform();
object.parent = cacheParent;
this.context.setTransform(1, 0, 0, 1, 0, 0);
this.context.globalAlpha = 1;
this.context.globalCompositeOperation = this.blendModes[CONST.BLEND_MODES.NORMAL];
if (navigator.isCocoonJS && this.view.screencanvas)
{
this.context.fillStyle = 'black';
this.context.clear();
}
if (this.clearBeforeRender)
{
if (this.transparent)
{
this.context.clearRect(0, 0, this.width, this.height);
}
else
{
this.context.fillStyle = this._backgroundColorString;
this.context.fillRect(0, 0, this.width , this.height);
}
}
this.renderDisplayObject(object, this.context);
this.emit('postrender');
};
/**
* Removes everything from the renderer and optionally removes the Canvas DOM element.
*
* @param [removeView=false] {boolean} Removes the Canvas element from the DOM.
*/
CanvasRenderer.prototype.destroy = function (removeView)
{
this.destroyPlugins();
// call the base destroy
SystemRenderer.prototype.destroy.call(this, removeView);
this.context = null;
this.refresh = true;
this.maskManager.destroy();
this.maskManager = null;
this.smoothProperty = null;
};
/**
* Renders a display object
*
* @param displayObject {PIXI.DisplayObject} The displayObject to render
* @private
*/
CanvasRenderer.prototype.renderDisplayObject = function (displayObject, context)
{
var tempContext = this.context;
this.context = context;
displayObject.renderCanvas(this);
this.context = tempContext;
};
/**
* @extends PIXI.SystemRenderer#resize
*
* @param {number} w
* @param {number} h
*/
CanvasRenderer.prototype.resize = function (w, h)
{
SystemRenderer.prototype.resize.call(this, w, h);
//reset the scale mode.. oddly this seems to be reset when the canvas is resized.
//surely a browser bug?? Let pixi fix that for you..
if(this.smoothProperty)
{
this.context[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR);
}
};
/**
* 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';
}
}
};