# src/pixi/renderers/CanvasRenderer.js - Pixi.JS

#

API Docs for: 1.0.0
Show: Inherited Protected Private Deprecated

# File: src/pixi/renderers/CanvasRenderer.js

    /**
     * @author Mat Groves http://matgroves.com/ @Doormat23
     */

    /**
     * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
     * Dont forget to add the view to your DOM or you will not see anything :)
     * @class CanvasRenderer
     * @constructor
     * @param width {Number} the width of the canvas view
     * @default 0
     * @param height {Number} the height of the canvas view
     * @default 0
     * @param view {Canvas} the canvas to use as a view, optional
     * @param transparent {Boolean} the transparency of the render view, default false
     * @default false
     *
     */
    PIXI.CanvasRenderer = function(width, height, view, transparent)
    {
    	this.transparent = transparent;

    	/**
    	 * The width of the canvas view
    	 * @property width
    	 * @type Number
    	 * @default 800
    	 */
    	this.width = width || 800;
    	/**
    	 * The height of the canvas view
    	 * @property height
    	 * @type Number
    	 * @default 600
    	 */
    	this.height = height || 600;

    	this.refresh = true;

    	/**
    	 * The canvas element that the everything is drawn to
    	 * @property view
    	 * @type Canvas
    	 */
    	this.view = view || document.createElement( 'canvas' );

    	// hack to enable some hardware acceleration!
    	//this.view.style["transform"] = "translatez(0)";

        this.view.width = this.width;
    	this.view.height = this.height;
    	this.count = 0;

    	/**
    	 * The canvas context that the everything is drawn to
    	 * @property context
    	 * @type Canvas 2d Context
    	 */
    	this.context = this.view.getContext("2d");
    }

    // constructor
    PIXI.CanvasRenderer.constructor = PIXI.CanvasRenderer;

    /**
     * Renders the stage to its canvas view
     * @method render
     * @param stage {Stage} the Stage element to be rendered
     */
    PIXI.CanvasRenderer.prototype.render = function(stage)
    {
    	// update children if need be

    	//stage.__childrenAdded = [];
    	//stage.__childrenRemoved = [];

    	// update textures if need be
    	PIXI.texturesToUpdate = [];
    	PIXI.texturesToDestroy = [];

    	stage.updateTransform();

    	// update the background color
    	if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString;

    	this.context.setTransform(1,0,0,1,0,0);
    	this.context.clearRect(0, 0, this.width, this.height)
        this.renderDisplayObject(stage);
        //as

        // run interaction!
    	if(stage.interactive)
    	{
    		//need to add some events!
    		if(!stage._interactiveEventsAdded)
    		{
    			stage._interactiveEventsAdded = true;
    			stage.interactionManager.setTarget(this);
    		}
    	}

    	// remove frame updates..
    	if(PIXI.Texture.frameUpdates.length > 0)
    	{
    		PIXI.Texture.frameUpdates = [];
    	}
    }

    /**
     * resizes the canvas view to the specified width and height
     * @param the new width of the canvas view
     * @param the new height of the canvas view
     */
    PIXI.CanvasRenderer.prototype.resize = function(width, height)
    {
    	this.width = width;
    	this.height = height;

    	this.view.width = width;
    	this.view.height = height;
    }

    /**
     * @private
     */

    PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject)
    {
    	var transform = displayObject.worldTransform;
    	var context = this.context;
    	//context.globalCompositeOperation = "source-over"
    	var blit = false;

    	if(!displayObject.visible)return;

    	if(displayObject instanceof PIXI.Sprite)
    	{
    		var frame = displayObject.texture.frame;

    		if(frame)
    		{
    			context.globalAlpha = displayObject.worldAlpha;

    			// BLITZ!!!
    			/*
    			 * if the rotation is 0 then we can blitz it
    			 * meaning we dont need to do a transform and also we
    			 * can round to the nearest round number for a little extra speed!
    			 */
    			/*if(displayObject.rotation == 0)
    			{
    				if(!blit)this.context.setTransform(1,0,0,1,0,0);
    				blit = true;
    				context.drawImage(displayObject.texture.baseTexture.image,
    								   frame.x,
    								   frame.y,
    								   frame.width,
    								   frame.height,
    								   (transform[2]+ ((displayObject.anchor.x - displayObject.texture.trim.x) * -frame.width) * transform[0]),
    								   (transform[5]+ ((displayObject.anchor.y - displayObject.texture.trim.y) * -frame.height)* transform[4]),
    								   (displayObject.width * transform[0]),
    								   (displayObject.height * transform[4]));

    			}
    			else
    			{*/
    			//	blit = false;
    				context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]);

    				context.drawImage(displayObject.texture.baseTexture.source,
    								   frame.x,
    								   frame.y,
    								   frame.width,
    								   frame.height,
    								   (displayObject.anchor.x) * -frame.width,
    								   (displayObject.anchor.y) * -frame.height,
    								 //   (displayObject.anchor.x - displayObject.texture.trim.x) * -frame.width,
    								  // (displayObject.anchor.y - displayObject.texture.trim.y) * -frame.height,

    								   frame.width,
    								   frame.height);
    			//}
    		}
       	}
       	else if(displayObject instanceof PIXI.Strip)
    	{
    		context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5])
    		this.renderStrip(displayObject);
    	}
    	else if(displayObject instanceof PIXI.TilingSprite)
    	{
    		context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5])
    		this.renderTilingSprite(displayObject);
    	}
    	else if(displayObject instanceof PIXI.CustomRenderable)
    	{
    		displayObject.renderCanvas(this);
    	}

    	// render!
    	for (var i=0; i < displayObject.children.length; i++)
    	{
    		this.renderDisplayObject(displayObject.children[i]);
    	}

    	this.context.setTransform(1,0,0,1,0,0);
    }

    /**
     * @private
     */
    PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip)
    {
    	var context = this.context;
    	var verticies = strip.verticies;
    	var uvs = strip.uvs;

    	var length = verticies.length/2;
    	this.count++;

    	context.beginPath();
    	for (var i=1; i < length-2; i++)
    	{

    		// draw some triangles!
    		var index = i*2;

    		 var x0 = verticies[index],   x1 = verticies[index+2], x2 = verticies[index+4];
     		 var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5];

    		context.moveTo(x0, y0);
    		context.lineTo(x1, y1);
    		context.lineTo(x2, y2);

    	};

    //	context.globalCompositeOperation = 'lighter';
    	context.fillStyle = "#FF0000";
    	context.fill();
    	context.closePath();
    	//context.globalCompositeOperation = 'source-over';
    }

    /**
     * @private
     */
    PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite)
    {
    	var context = this.context;

     	if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat");

    	context.beginPath();

    	var tilePosition = sprite.tilePosition;
    	var tileScale = sprite.tileScale;

        // offset
        context.scale(tileScale.x,tileScale.y);
        context.translate(tilePosition.x, tilePosition.y);

    	context.fillStyle = sprite.__tilePattern;
    	context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y);

    	context.scale(1/tileScale.x, 1/tileScale.y);
        context.translate(-tilePosition.x, -tilePosition.y);

        context.closePath();
    }

    /**
     * @private
     */
    PIXI.CanvasRenderer.prototype.renderStrip = function(strip)
    {
    	var context = this.context;
    	//context.globalCompositeOperation = 'lighter';
    	// draw triangles!!
    	var verticies = strip.verticies;
    	var uvs = strip.uvs;

    	var length = verticies.length/2;
    	this.count++;
    	for (var i=1; i < length-2; i++)
    	{

    		// draw some triangles!
    		var index = i*2;

    		 var x0 = verticies[index],   x1 = verticies[index+2], x2 = verticies[index+4];
     		 var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5];

      		 var u0 = uvs[index] * strip.texture.width,   u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width;
       		 var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height;

    		context.save();
    		context.beginPath();
    		context.moveTo(x0, y0);
    		context.lineTo(x1, y1);
    		context.lineTo(x2, y2);
    		context.closePath();

    	//	context.fillStyle = "white"//rgb(1, 1, 1,1));
    	//	context.fill();
    		context.clip();

            // Compute matrix transform
            var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2;
            var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2;
            var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2;
            var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2;
            var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2;
            var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2;
            var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2;

            context.transform(delta_a/delta, delta_d/delta,
                          delta_b/delta, delta_e/delta,
                          delta_c/delta, delta_f/delta);

    		context.drawImage(strip.texture.baseTexture.source, 0, 0);
    	  	context.restore();
    	};

    //	context.globalCompositeOperation = 'source-over';
    }