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) { 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 {CanvasMaskManager} */ this.maskManager = new CanvasMaskManager(); /** * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation. * Handy for crisp pixel art and speed on legacy devices. * * @member {boolean} */ this.roundPixels = options.roundPixels === true; /** * Tracks the active scale mode for this renderer. * * @member {SCALE_MODE} */ this.currentScaleMode = CONST.SCALE_MODES.DEFAULT; /** * Tracks the active blend mode for this renderer. * * @member {SCALE_MODE} */ this.currentBlendMode = CONST.BLEND_MODES.NORMAL; /** * 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 {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 {DisplayObject} the object to be rendered */ CanvasRenderer.prototype.render = function (object) { 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.currentBlendMode = CONST.BLEND_MODES.NORMAL; 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); }; /** * 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.roundPixels = false; this.currentScaleMode = 0; this.currentBlendMode = 0; this.smoothProperty = null; }; /** * Renders a display object * * @param displayObject {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; }; 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.. this.currentScaleMode = CONST.SCALE_MODES.DEFAULT; if(this.smoothProperty) { this.context[this.smoothProperty] = (this.currentScaleMode === 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'; } } };