//  Based on code from https://github.com/WesUnwin/obj-file-parser

var Vector3 = require('../../math/Vector3');

var models = [];
var materialLibraries = [];
var vertices = [ null ];
var textureCoords = [ null ];
var vertexNormals = [ null ];
var currentModel;
var currentMaterial = '';
var currentGroup = '';
var smoothingGroup = 0;
var maxVertices = 0;

function addModel (name)
{
    //  Inject empty vec3 because face vertice indexes are 1 based and the array is zero based
    currentModel = {
        name: name,
        faces: []
    };

    models.push(currentModel);

    currentGroup = '';
    smoothingGroup = 0;
}

function getCurrentModel ()
{
    if (models.length === 0)
    {
        addModel('model0');
    }

    return currentModel;
}

function parseObject (lineItems)
{
    var modelName = (lineItems.length >= 2) ? lineItems[1] : 'model' + models.length;

    addModel(modelName);
}

function parseGroup (lineItems)
{
    if (lineItems.length === 2)
    {
        currentGroup = lineItems[1];
    }
}

function parseSmoothShadingStatement (lineItems)
{
    if (lineItems.length === 2)
    {
        smoothingGroup = (lineItems[1].toLowerCase() === 'off') ? 0 : parseInt(lineItems[1]);
    }
}

function parseMtlLib (lineItems)
{
    if (lineItems.length >= 2)
    {
        materialLibraries.push(lineItems[1]);
    }
}

function parseUseMtl (lineItems)
{
    if (lineItems.length >= 2)
    {
        currentMaterial = lineItems[1];
    }
}

function parseVertexCoords (lineItems)
{
    var x = (lineItems.length >= 2) ? parseFloat(lineItems[1]) : 0;
    var y = (lineItems.length >= 3) ? parseFloat(lineItems[2]) : 0;
    var z = (lineItems.length >= 4) ? parseFloat(lineItems[3]) : 0;

    vertices.push(new Vector3(x, y, z));
}

function parseTextureCoords (lineItems)
{
    var u = (lineItems.length >= 2) ? parseFloat(lineItems[1]) : 0;
    var v = (lineItems.length >= 3) ? parseFloat(lineItems[2]) : 0;
    var w = (lineItems.length >= 4) ? parseFloat(lineItems[3]) : 0;

    textureCoords.push({ u: u, v: v, w: w });
}

function parseVertexNormal (lineItems)
{
    var x = (lineItems.length >= 2) ? parseFloat(lineItems[1]) : 0;
    var y = (lineItems.length >= 3) ? parseFloat(lineItems[2]) : 0;
    var z = (lineItems.length >= 4) ? parseFloat(lineItems[3]) : 0;

    vertexNormals.push(new Vector3(x, y, z));
}

function parsePolygon (lineItems)
{
    var totalVertices = (lineItems.length - 1);

    if (totalVertices < 3)
    {
        return;
    }

    if (totalVertices > maxVertices)
    {
        maxVertices = totalVertices;
    }

    //  0 = tri
    //  1 = quad / poly
    var type = (totalVertices > 3) ? 1 : 0;

    var face = {
        material: currentMaterial,
        group: currentGroup,
        smoothingGroup: smoothingGroup,
        type: type,
        vertices: []
    };

    for (var i = 0; i < totalVertices; i++)
    {
        var vertexString = lineItems[i + 1];

        //  Are the values split by a forward-slash (Wavefront style) or a space (Blender style) ?

        var vertexValues;

        var index = vertexString.indexOf('/');

        if (index > -1)
        {
            vertexValues = vertexString.split('/');
        }
        else
        {
            vertexValues = vertexString.split(' ');
        }

        if (vertexValues.length < 1 || vertexValues.length > 3)
        {
            //  Too many values (separated by /) for a single vertex
            return;
        }

        //  Vertex Indicies:
        // f v1 v2 v3 ....

        //  Vertex Texture Coordinate Indices
        // f v1/vt1 v2/vt2 v3/vt3 ...

        // Vertex Normal Indices
        // f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...

        // Vertex Normal Indices Without Texture Coordinate Indices
        // f v1//vn1 v2//vn2 v3//vn3 ...

        var vertexIndex = parseInt(vertexValues[0]);
        var textureCoordsIndex = 0;
        var vertexNormalIndex = 0;

        if (vertexValues.length > 1 && (!vertexValues[1] === ''))
        {
            textureCoordsIndex = parseInt(vertexValues[1]);
        }

        if (vertexValues.length > 2)
        {
            vertexNormalIndex = parseInt(vertexValues[2]);
        }

        if (vertexIndex === 0)
        {
            //  Faces uses invalid vertex index of 0
            return;
        }

        //  Negative vertex indices refer to the nth last defined vertex
        //  convert these to postive indices for simplicity
        if (vertexIndex < 0)
        {
            vertexIndex = getCurrentModel().vertices.length + 1 + vertexIndex;
        }

        face.vertices.push({
            vertexIndex: vertexIndex,
            textureCoordsIndex: textureCoordsIndex,
            vertexNormalIndex: vertexNormalIndex
        });
    }

    getCurrentModel().faces.push(face);
}

function stripComments (line)
{
    var index = line.indexOf('#');

    if (index > -1)
    {
        return line.substring(0, index);
    }

    return line;
}

function reset ()
{
    models = [];
    materialLibraries = [];
    vertices = [ null ];
    textureCoords = [ null ];
    vertexNormals = [ null ];
    currentModel;
    currentMaterial = '';
    currentGroup = '';
    smoothingGroup = 0;
    maxVertices = 0;
}

var ParseOBJ = function (data)
{
    reset();

    var lines = data.split('\n');

    for (var i = 0; i < lines.length; i++)
    {
        var line = stripComments(lines[i]);

        var lineItems = line.replace(/\s\s+/g, ' ').trim().split(' ');

        switch (lineItems[0].toLowerCase())
        {
            case 'o':
                // Start a New Model
                parseObject(lineItems);
                break;

            case 'g':
                // Start a new polygon group
                parseGroup(lineItems);
                break;

            case 'v':
                // Define a vertex for the current model
                parseVertexCoords(lineItems);
                break;

            case 'vt':
                // Texture Coords
                parseTextureCoords(lineItems);
                break;

            case 'vn':
                // Define a vertex normal for the current model
                parseVertexNormal(lineItems);
                break;

            case 's':
                // Smooth shading statement
                parseSmoothShadingStatement(lineItems);
                break;

            case 'f':
                // Define a Face/Polygon
                parsePolygon(lineItems);
                break;

            case 'mtllib':
                // Reference to a material library file (.mtl)
                parseMtlLib(lineItems);
                break;

            case 'usemtl':
                // Sets the current material to be applied to polygons defined from this point forward
                parseUseMtl(lineItems);
                break;
        }
    }

    return {
        vertices: vertices,
        textureCoords: textureCoords,
        vertexNormals: vertexNormals,
        models: models,
        materialLibraries: materialLibraries,
        maxVertices: maxVertices
    };
};

module.exports = ParseOBJ;


var renderTiles = gameObject.culledTiles;

var texture = gameObject.texture.source[0].glTexture;

var renderTarget = gameObject.renderTarget;

keep keep keep keep replace keep keep keep keep

var texture = gameObject.tileset.image.get().source.glTexture;

/**
 * [description]
 *
 * @function Phaser.Math.Angle.Normalize
 * @since 3.0.0
 *
 * @param {number} angle - [description]
 *
 * @return {number} [description]
 */
var Normalize = function (angle)
{
    angle = angle % (2 * Math.PI);

    if (angle >= 0)
    {
        return angle;
    }
    else
    {
        return angle + 2 * Math.PI;
    }
};

module.exports = Normalize;


keep keep keep keep replace keep keep keep

var Class = require('../../../utils/Class');
var GameObject = require('../../GameObject');
var Components = require('../../components');
var DynamicTilemapLayerRender = require('./DynamicTilemapLayerRender');
var TilemapComponents = require('../components');

var DynamicTilemapLayer = new Class({

    Extends: GameObject,

    Mixins: [
        Components.Alpha,
        Components.BlendMode,
        Components.Flip,
        Components.GetBounds,
        Components.Origin,
        Components.RenderTarget,
        Components.ScaleMode,
        Components.Size,
        Components.Texture,
        Components.Transform,
        Components.Visible,
        Components.ScrollFactor,
        DynamicTilemapLayerRender
    ],

    initialize:

    /**
     * A DynamicTilemapLayer is a game object that renders LayerData from a Tilemap. A
     * DynamicTilemapLayer can only render tiles from a single tileset.
     *
     * A DynamicTilemapLayer trades some speed for being able to apply powerful effects. Unlike a
     * StaticTilemapLayer, you can apply per-tile effects like tint or alpha, and you can change the
     * tiles in a DynamicTilemapLayer. Use this over a StaticTilemapLayer when you need those
     * features.
     *
     * @class DynamicTilemapLayer
     * @constructor
     *
     * @param {Scene} scene - [description]
     * @param {Tilemap} tilemap - The Tilemap this layer is a part of.
     * @param {integer} layerIndex - The index of the LayerData associated with this layer.
     * @param {Tileset} tileset - The tileset used to render the tiles in this layer.
     * @param {number} [x=0] - The world x position where the top left of this layer will be placed.
     * @param {number} [y=0] - The world y position where the top left of this layer will be placed.
     */
    function DynamicTilemapLayer (scene, tilemap, layerIndex, tileset, x, y)
    {
        GameObject.call(this, scene, 'DynamicTilemapLayer');

        /**
         * Used internally by physics system to perform fast type checks.
         * @property {boolean} isTilemap
         * @readonly
         */
        this.isTilemap = true;

        /**
         * The Tilemap that this layer is a part of.
         * @property {Tilemap} map
         */
        this.map = tilemap;

        /**
         * The index of the LayerData associated with this layer.
         * @property {integer} layerIndex
         */
        this.layerIndex = layerIndex;

        /**
         * The LayerData associated with this layer. LayerData can only be associated with one
         * tilemap layer.
         * @property {LayerData} layerIndex
         */
        this.layer = tilemap.layers[layerIndex];
        this.layer.tilemapLayer = this; // Link the LayerData with this static tilemap layer

        /**
         * The Tileset associated with this layer. A tilemap layer can only render from one Tileset.
         * @property {Tileset} tileset
         */
        this.tileset = tileset;

        /**
         * Used internally with the canvas render. This holds the tiles that are visible within the
         * camera.
         * @property {Tileset} culledTiles
         */
        this.culledTiles = [];

        this.setAlpha(this.layer.alpha);
        this.setTexture(tileset.image.key);
        this.setPosition(x, y);
        this.setSizeToFrame();
        this.setOrigin();
        this.setSize(this.layer.tileWidth * this.layer.width, this.layer.tileHeight * this.layer.height);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    calculateFacesWithin: function (tileX, tileY, width, height)
    {
        TilemapComponents.CalculateFacesWithin(tileX, tileY, width, height, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Sprite[]}
     */
    createFromTiles: function (indexes, replacements, spriteConfig, scene, camera)
    {
        return TilemapComponents.CreateFromTiles(indexes, replacements, spriteConfig, scene, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    cull: function (camera)
    {
        return TilemapComponents.CullTiles(this.layer, camera, this.culledTiles);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    copy: function (srcTileX, srcTileY, width, height, destTileX, destTileY, recalculateFaces)
    {
        TilemapComponents.Copy(srcTileX, srcTileY, width, height, destTileX, destTileY, recalculateFaces, this.layer);
        return this;
    },

    /**
    * Destroys this DynamicTilemapLayer and removes its link to the associated LayerData.
    *
    * @method Phaser.TilemapLayer#destroy
    */
    destroy: function ()
    {
        // Uninstall this layer only if it is still installed on the LayerData object
        if (this.layer.tilemapLayer === this)
        {
            this.layer.tilemapLayer = undefined;
        }
        this.map = undefined;
        this.layer = undefined;
        this.tileset = undefined;
        this.culledTiles.length = 0;
        GameObject.prototype.destroy.call(this);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    fill: function (index, tileX, tileY, width, height, recalculateFaces)
    {
        TilemapComponents.Fill(index, tileX, tileY, width, height, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    filterTiles: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.FilterTiles(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    findByIndex: function (findIndex, skip, reverse)
    {
        return TilemapComponents.FindByIndex(findIndex, skip, reverse, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile|null}
     */
    findTile: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.FindTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    forEachTile: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        TilemapComponents.ForEachTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    getTileAt: function (tileX, tileY, nonNull)
    {
        return TilemapComponents.GetTileAt(tileX, tileY, nonNull, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    getTileAtWorldXY: function (worldX, worldY, nonNull, camera)
    {
        return TilemapComponents.GetTileAtWorldXY(worldX, worldY, nonNull, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithin: function (tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.GetTilesWithin(tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithinShape: function (shape, filteringOptions, camera)
    {
        return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithinWorldXY: function (worldX, worldY, width, height, filteringOptions, camera)
    {
        return TilemapComponents.GetTilesWithinWorldXY(worldX, worldY, width, height, filteringOptions, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {boolean}
     */
    hasTileAt: function (tileX, tileY)
    {
        return TilemapComponents.HasTileAt(tileX, tileY, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {boolean}
     */
    hasTileAtWorldXY: function (worldX, worldY, camera)
    {
        return TilemapComponents.HasTileAtWorldXY(worldX, worldY, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    putTileAt: function (tile, tileX, tileY, recalculateFaces)
    {
        return TilemapComponents.PutTileAt(tile, tileX, tileY, recalculateFaces, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    putTileAtWorldXY: function (tile, worldX, worldY, recalculateFaces, camera)
    {
        return TilemapComponents.PutTileAtWorldXY(tile, worldX, worldY, recalculateFaces, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    putTilesAt: function (tilesArray, tileX, tileY, recalculateFaces)
    {
        TilemapComponents.PutTilesAt(tilesArray, tileX, tileY, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    randomize: function (tileX, tileY, width, height, indexes)
    {
        TilemapComponents.Randomize(tileX, tileY, width, height, indexes, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    removeTileAt: function (tileX, tileY, replaceWithNull, recalculateFaces)
    {
        return TilemapComponents.RemoveTileAt(tileX, tileY, replaceWithNull, recalculateFaces, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    removeTileAtWorldXY: function (worldX, worldY, replaceWithNull, recalculateFaces, camera)
    {
        return TilemapComponents.RemoveTileAtWorldXY(worldX, worldY, replaceWithNull, recalculateFaces, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    renderDebug: function (graphics, styleConfig)
    {
        TilemapComponents.RenderDebug(graphics, styleConfig, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    replaceByIndex: function (findIndex, newIndex, tileX, tileY, width, height)
    {
        TilemapComponents.ReplaceByIndex(findIndex, newIndex, tileX, tileY, width, height, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollision: function (indexes, collides, recalculateFaces)
    {
        TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollisionBetween: function (start, stop, collides, recalculateFaces)
    {
        TilemapComponents.SetCollisionBetween(start, stop, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollisionByExclusion: function (indexes, collides, recalculateFaces)
    {
        TilemapComponents.SetCollisionByExclusion(indexes, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setTileIndexCallback: function (indexes, callback, callbackContext)
    {
        TilemapComponents.SetTileIndexCallback(indexes, callback, callbackContext, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setTileLocationCallback: function (tileX, tileY, width, height, callback, callbackContext)
    {
        TilemapComponents.SetTileLocationCallback(tileX, tileY, width, height, callback, callbackContext, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    shuffle: function (tileX, tileY, width, height)
    {
        TilemapComponents.Shuffle(tileX, tileY, width, height, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    swapByIndex: function (indexA, indexB, tileX, tileY, width, height)
    {
        TilemapComponents.SwapByIndex(indexA, indexB, tileX, tileY, width, height, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    tileToWorldX: function (tileX, camera)
    {
        return TilemapComponents.TileToWorldX(tileX, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    tileToWorldY: function (tileY, camera)
    {
        return TilemapComponents.TileToWorldY(tileY, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Vector2}
     */
    tileToWorldXY: function (tileX, tileY, point, camera)
    {
        return TilemapComponents.TileToWorldXY(tileX, tileY, point, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    weightedRandomize: function (tileX, tileY, width, height, weightedIndexes)
    {
        TilemapComponents.WeightedRandomize(tileX, tileY, width, height, weightedIndexes, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    worldToTileX: function (worldX, snapToFloor, camera)
    {
        return TilemapComponents.WorldToTileX(worldX, snapToFloor, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    worldToTileY: function (worldY, snapToFloor, camera)
    {
        return TilemapComponents.WorldToTileY(worldY, snapToFloor, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Vector}
     */
    worldToTileXY: function (worldX, worldY, snapToFloor, point, camera)
    {
        return TilemapComponents.WorldToTileXY(worldX, worldY, snapToFloor, point, camera, this.layer);
    }

});

module.exports = DynamicTilemapLayer;


/**
* Note that 'this' in all functions here refer to the owning object.
* For example the Group, Stage, Sprite, etc. because the render function
* here is mapped to the prototype for the game object.
*/
Phaser.Renderer.Canvas.GameObjects.Graphics = {

    TYPES: [
        Phaser.GameObject.Graphics.prototype
    ],

    render: function (renderer, src)
    {
        var context = renderer.context;

        if (this.dirty)
        {
            this.updateGraphicsTint();

            this.dirty = false;
        }

        for (var i = 0; i < this.graphicsData.length; i++)
        {
            var data = this.graphicsData[i];

            context.lineWidth = data.lineWidth;

            switch (data.type)
            {
                case Phaser.RECTANGLE:
                    Phaser.Renderer.Canvas.GameObjects.Graphics.drawRectangle(data, context);
                    break;

                case Phaser.CIRCLE:
                    Phaser.Renderer.Canvas.GameObjects.Graphics.drawCircle(data, context);
                    break;

                case Phaser.POLYGON:
                    Phaser.Renderer.Canvas.GameObjects.Graphics.drawPolygon(data, context);
                    break;

                case Phaser.ELLIPSE:
                    Phaser.Renderer.Canvas.GameObjects.Graphics.drawEllipse(data, context);
                    break;

                case Phaser.ROUNDEDRECTANGLE:
                    Phaser.Renderer.Canvas.GameObjects.Graphics.drawRoundedRectangle(data, context);
                    break;
            }
        }

    },

    drawRectangle: function (data, context)
    {
        var shape = data.shape;

        if (data.fillColor || data.fillColor === 0)
        {
            context.globalAlpha = data.fillAlpha * this.worldAlpha;
            context.fillStyle = '#' + ('00000' + (data._fillTint | 0).toString(16)).substr(-6);
            context.fillRect(shape.x, shape.y, shape.width, shape.height);
        }

        if (data.lineWidth)
        {
            context.globalAlpha = data.lineAlpha * this.worldAlpha;
            context.strokeStyle = '#' + ('00000' + (data._lineTint | 0).toString(16)).substr(-6);
            context.strokeRect(shape.x, shape.y, shape.width, shape.height);
        }

    },

    drawRoundedRectangle: function (data, context)
    {
        var shape = data.shape;

        var rx = shape.x;
        var ry = shape.y;
        var width = shape.width;
        var height = shape.height;
        var radius = shape.radius;

        var maxRadius = Math.min(width, height) / 2 | 0;
        radius = radius > maxRadius ? maxRadius : radius;

        context.beginPath();
        context.moveTo(rx, ry + radius);
        context.lineTo(rx, ry + height - radius);
        context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
        context.lineTo(rx + width - radius, ry + height);
        context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
        context.lineTo(rx + width, ry + radius);
        context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
        context.lineTo(rx + radius, ry);
        context.quadraticCurveTo(rx, ry, rx, ry + radius);
        context.closePath();

        if (data.fillColor || data.fillColor === 0)
        {
            context.globalAlpha = data.fillAlpha * this.worldAlpha;
            context.fillStyle = '#' + ('00000' + (data._fillTint | 0).toString(16)).substr(-6);
            context.fill();
        }

        if (data.lineWidth)
        {
            context.globalAlpha = data.lineAlpha * this.worldAlpha;
            context.strokeStyle = '#' + ('00000' + (data._lineTint | 0).toString(16)).substr(-6);
            context.stroke();
        }

    },

    drawEllipse: function (data, context)
    {
        var shape = data.shape;

        // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas

        var w = shape.width * 2;
        var h = shape.height * 2;

        var x = shape.x - (w / 2);
        var y = shape.y - (h / 2);

        context.beginPath();

        var kappa = 0.5522848;
        var ox = (w / 2) * kappa;   // control point offset horizontal
        var oy = (h / 2) * kappa;   // control point offset vertical
        var xe = x + w;             // x-end
        var ye = y + h;             // y-end
        var xm = x + (w / 2);       // x-middle
        var ym = y + (h / 2);       // y-middle

        context.moveTo(x, ym);
        context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
        context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
        context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
        context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);

        context.closePath();

        if (data.fill)
        {
            context.globalAlpha = data.fillAlpha * this.worldAlpha;
            context.fillStyle = '#' + ('00000' + (data._fillTint | 0).toString(16)).substr(-6);
            context.fill();
        }

        if (data.lineWidth)
        {
            context.globalAlpha = data.lineAlpha * this.worldAlpha;
            context.strokeStyle = '#' + ('00000' + (data._lineTint | 0).toString(16)).substr(-6);
            context.stroke();
        }

    },

    drawCircle: function (data, context)
    {
        var shape = data.shape;

        context.beginPath();
        context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI);
        context.closePath();

        if (data.fill)
        {
            context.globalAlpha = data.fillAlpha * this.worldAlpha;
            context.fillStyle = '#' + ('00000' + (data._fillTint | 0).toString(16)).substr(-6);
            context.fill();
        }

        if (data.lineWidth)
        {
            context.globalAlpha = data.lineAlpha * this.worldAlpha;
            context.strokeStyle = '#' + ('00000' + (data._lineTint | 0).toString(16)).substr(-6);
            context.stroke();
        }

    },

    drawPolygon: function (data, context)
    {
        var shape = data.shape;

        context.beginPath();

        var points = shape.points;

        context.moveTo(points[0], points[1]);

        for (var j = 1; j < points.length / 2; j++)
        {
            context.lineTo(points[j * 2], points[j * 2 + 1]);
        }

        if (shape.closed)
        {
            context.lineTo(points[0], points[1]);
        }

        // if the first and last point are the same close the path - much neater :)
        if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1])
        {
            context.closePath();
        }

        if (data.fill)
        {
            context.globalAlpha = data.fillAlpha * this.worldAlpha;
            context.fillStyle = '#' + ('00000' + (data._fillTint | 0).toString(16)).substr(-6);
            context.fill();
        }

        if (data.lineWidth)
        {
            context.globalAlpha = data.lineAlpha * this.worldAlpha;
            context.strokeStyle = '#' + ('00000' + (data._lineTint | 0).toString(16)).substr(-6);
            context.stroke();
        }

    }

};


var Camera = require('../../cameras/2d/Camera.js');
var CanvasPool = require('../../display/canvas/CanvasPool');
var Class = require('../../utils/Class');
var Commands = require('./Commands');
var Components = require('../components');
var Ellipse = require('../../geom/ellipse/');
var GameObject = require('../GameObject');
var GetValue = require('../../utils/object/GetValue');
var MATH_CONST = require('../../math/const');
var Matrix4 = require('../../math/Matrix4');
var Mesh = require('../../geom/mesh/Mesh');
var Render = require('./GraphicsRender');
var Vector3 = require('../../math/Vector3');

var Graphics = new Class({

    Extends: GameObject,

    Mixins: [
        Components.Alpha,
        Components.BlendMode,
        Components.Transform,
        Components.RenderTarget,
        Components.Visible,
        Components.ScrollFactor,
        Render
    ],

    initialize:

    function Graphics (scene, options)
    {
        var x = GetValue(options, 'x', 0);
        var y = GetValue(options, 'y', 0);

        GameObject.call(this, scene, 'Graphics');

        this.setPosition(x, y);

        this.displayOriginX = 0;
        this.displayOriginY = 0;

        this.commandBuffer = [];

        this.defaultFillColor = -1;
        this.defaultFillAlpha = 1;

        this.defaultStrokeWidth = 1;
        this.defaultStrokeColor = -1;
        this.defaultStrokeAlpha = 1;
        this._lineWidth = 1.0;

        this.setDefaultStyles(options);

        //  Mesh viewport camera

        this.viewportWidth = scene.sys.game.config.width;
        this.viewportHeight = scene.sys.game.config.height;

        this.camera = {
            position: new Vector3(),
            target: new Vector3()
        };

        this.up = new Vector3().up();
        this.projectionMatrix = new Matrix4();
        this.viewMatrix = new Matrix4().lookAt(this.camera.position, this.camera.target, this.up);

        this.setViewport(this.viewportWidth, this.viewportHeight);

        var resourceManager = scene.sys.game.renderer.resourceManager;

        if (resourceManager !== undefined)
        {
            this.resourceManager = resourceManager;
            this.gl = scene.sys.game.renderer.gl;
        }
    },

    //  STYLES

    setDefaultStyles: function (options)
    {
        if (GetValue(options, 'lineStyle', null))
        {
            this.defaultStrokeWidth = GetValue(options, 'lineStyle.width', 1);
            this.defaultStrokeColor = GetValue(options, 'lineStyle.color', 0xffffff);
            this.defaultStrokeAlpha = GetValue(options, 'lineStyle.alpha', 1);

            this.lineStyle(this.defaultStrokeWidth, this.defaultStrokeColor, this.defaultStrokeAlpha);
        }

        if (GetValue(options, 'fillStyle', null))
        {
            this.defaultFillColor = GetValue(options, 'fillStyle.color', 0xffffff);
            this.defaultFillAlpha = GetValue(options, 'fillStyle.alpha', 1);

            this.fillStyle(this.defaultFillColor, this.defaultFillAlpha);
        }

        return this;
    },

    lineStyle: function (lineWidth, color, alpha)
    {
        if (alpha === undefined) { alpha = 1; }

        this.commandBuffer.push(
            Commands.LINE_STYLE,
            lineWidth, color, alpha
        );

        this._lineWidth = lineWidth;

        return this;
    },

    fillStyle: function (color, alpha)
    {
        if (alpha === undefined) { alpha = 1; }

        this.commandBuffer.push(
            Commands.FILL_STYLE,
            color, alpha
        );

        return this;
    },

    //  PATH

    beginPath: function ()
    {
        this.commandBuffer.push(
            Commands.BEGIN_PATH
        );

        return this;
    },

    closePath: function ()
    {
        this.commandBuffer.push(
            Commands.CLOSE_PATH
        );

        return this;
    },

    fillPath: function ()
    {
        this.commandBuffer.push(
            Commands.FILL_PATH
        );

        return this;
    },

    strokePath: function ()
    {
        this.commandBuffer.push(
            Commands.STROKE_PATH
        );

        return this;
    },

    //  CIRCLE

    fillCircleShape: function (circle)
    {
        return this.fillCircle(circle.x, circle.y, circle.radius);
    },

    strokeCircleShape: function (circle)
    {
        return this.strokeCircle(circle.x, circle.y, circle.radius);
    },

    fillCircle: function (x, y, radius)
    {
        this.beginPath();
        this.arc(x, y, radius, 0, MATH_CONST.PI2);
        this.closePath();
        this.fillPath();

        return this;
    },

    strokeCircle: function (x, y, radius)
    {
        this.beginPath();
        this.arc(x, y, radius, 0, MATH_CONST.PI2);
        this.closePath();
        this.strokePath();

        return this;
    },

    //  RECTANGLE

    fillRectShape: function (rect)
    {
        return this.fillRect(rect.x, rect.y, rect.width, rect.height);
    },

    strokeRectShape: function (rect)
    {
        return this.strokeRect(rect.x, rect.y, rect.width, rect.height);
    },

    fillRect: function (x, y, width, height)
    {
        this.commandBuffer.push(
            Commands.FILL_RECT,
            x, y, width, height
        );

        return this;
    },

    strokeRect: function (x, y, width, height)
    {
        var lineWidthHalf = this._lineWidth / 2;
        var minx = x - lineWidthHalf;
        var maxx = x + lineWidthHalf;

        this.beginPath();
        this.moveTo(x, y);
        this.lineTo(x, y + height);
        this.strokePath();
        this.closePath();

        this.beginPath();
        this.moveTo(x + width, y);
        this.lineTo(x + width, y + height);
        this.strokePath();
        this.closePath();

        this.beginPath();
        this.moveTo(minx, y);
        this.lineTo(maxx + width, y);
        this.strokePath();
        this.closePath();

        this.beginPath();
        this.moveTo(minx, y + height);
        this.lineTo(maxx + width, y + height);
        this.strokePath();
        this.closePath();

        return this;
    },

    //  POINT

    fillPointShape: function (point, size)
    {
        return this.fillPoint(point.x, point.y, size);
    },

    fillPoint: function (x, y, size)
    {
        this.commandBuffer.push(
            Commands.FILL_RECT,
            x, y, size, size
        );

        return this;
    },

    //  TRIANGLE

    fillTriangleShape: function (triangle)
    {
        return this.fillTriangle(triangle.x1, triangle.y1, triangle.x2, triangle.y2, triangle.x3, triangle.y3);
    },

    strokeTriangleShape: function (triangle)
    {
        return this.strokeTriangle(triangle.x1, triangle.y1, triangle.x2, triangle.y2, triangle.x3, triangle.y3);
    },

    fillTriangle: function (x0, y0, x1, y1, x2, y2)
    {
        this.commandBuffer.push(
            Commands.FILL_TRIANGLE,
            x0, y0, x1, y1, x2, y2
        );

        return this;
    },

    strokeTriangle: function (x0, y0, x1, y1, x2, y2)
    {
        this.commandBuffer.push(
            Commands.STROKE_TRIANGLE,
            x0, y0, x1, y1, x2, y2
        );

        return this;
    },

    //  LINE

    strokeLineShape: function (line)
    {
        return this.lineBetween(line.x1, line.y1, line.x2, line.y2);
    },

    lineBetween: function (x1, y1, x2, y2)
    {
        this.beginPath();
        this.moveTo(x1, y1);
        this.lineTo(x2, y2);
        this.strokePath();

        return this;
    },

    lineTo: function (x, y)
    {
        this.commandBuffer.push(
            Commands.LINE_TO,
            x, y
        );

        return this;
    },

    moveTo: function (x, y)
    {
        this.commandBuffer.push(
            Commands.MOVE_TO,
            x, y
        );

        return this;
    },

    lineFxTo: function (x, y, width, rgb)
    {
        this.commandBuffer.push(
            Commands.LINE_FX_TO,
            x, y, width, rgb, 1
        );

        return this;
    },

    moveFxTo: function (x, y, width, rgb)
    {
        this.commandBuffer.push(
            Commands.MOVE_FX_TO,
            x, y, width, rgb, 1
        );

        return this;
    },

    //  STROKE LINES BETWEEN AN ARRAY OF POINTS

    strokePoints: function (points, autoClose, endIndex)
    {
        if (autoClose === undefined) { autoClose = false; }
        if (endIndex === undefined) { endIndex = points.length; }

        this.beginPath();

        this.moveTo(points[0].x, points[0].y);

        for (var i = 1; i < endIndex; i++)
        {
            this.lineTo(points[i].x, points[i].y);
        }

        if (autoClose)
        {
            this.lineTo(points[0].x, points[0].y);
        }

        this.strokePath();

        return this;
    },

    fillPoints: function (points, autoClose, endIndex)
    {
        if (autoClose === undefined) { autoClose = false; }
        if (endIndex === undefined) { endIndex = points.length; }

        this.beginPath();

        this.moveTo(points[0].x, points[0].y);

        for (var i = 1; i < endIndex; i++)
        {
            this.lineTo(points[i].x, points[i].y);
        }

        if (autoClose)
        {
            this.lineTo(points[0].x, points[0].y);
        }

        this.fillPath();

        return this;
    },

    //  ELLIPSE

    strokeEllipseShape: function (ellipse, smoothness)
    {
        if (smoothness === undefined) { smoothness = 32; }

        var points = ellipse.getPoints(smoothness);

        return this.strokePoints(points, true);
    },

    strokeEllipse: function (x, y, width, height, smoothness)
    {
        if (smoothness === undefined) { smoothness = 32; }

        var ellipse = new Ellipse(x, y, width, height);

        var points = ellipse.getPoints(smoothness);

        return this.strokePoints(points, true);
    },

    //  ARC

    arc: function (x, y, radius, startAngle, endAngle, anticlockwise)
    {
        this.commandBuffer.push(
            Commands.ARC,
            x, y, radius, startAngle, endAngle, anticlockwise
        );

        return this;
    },

    //  MESH + VIEWPORT + CAMERA

    cameraX: {

        get: function ()
        {
            return this.camera.position.x;
        },

        set: function (value)
        {
            this.camera.position.x = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    cameraY: {

        get: function ()
        {
            return this.camera.position.y;
        },

        set: function (value)
        {
            this.camera.position.y = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    cameraZ: {

        get: function ()
        {
            return this.camera.position.z;
        },

        set: function (value)
        {
            this.camera.position.z = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    cameraTargetX: {

        get: function ()
        {
            return this.camera.target.x;
        },

        set: function (value)
        {
            this.camera.target.x = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    cameraTargetY: {

        get: function ()
        {
            return this.camera.target.y;
        },

        set: function (value)
        {
            this.camera.target.y = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    cameraTargetZ: {

        get: function ()
        {
            return this.camera.target.z;
        },

        set: function (value)
        {
            this.camera.target.z = value;
            this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);
        }

    },

    setCameraPosition: function (x, y, z)
    {
        this.camera.position.set(x, y, z);

        this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);

        return this;
    },

    setCameraTarget: function (x, y, z)
    {
        this.camera.target.set(x, y, z);

        this.viewMatrix.lookAt(this.camera.position, this.camera.target, this.up);

        return this;
    },

    // @param {number} fovy Vertical field of view in radians
    // @param {number} near Near bound of the frustum
    // @param {number} far Far bound of the frustum
    setViewport: function (width, height, fov, near, far)
    {
        if (fov === undefined) { fov = 0.8; }
        if (near === undefined) { near = 0.01; }
        if (far === undefined) { far = 1; }

        this.viewportWidth = width;
        this.viewportHeight = height;

        //  fov, aspect, near, far
        this.projectionMatrix.perspective(fov, width / height, near, far);

        return this;
    },

    //  Allow key to be a data array OR object containing the rest of the properties + color etc
    createMesh: function (key, x, y, z)
    {
        var data = this.scene.sys.cache.obj.get(key);

        var mesh = new Mesh(data, x, y, z);

        return mesh;
    },

    fillMesh: function (mesh)
    {
        mesh.fill(this);

        return this;
    },

    strokeMesh: function (mesh)
    {
        mesh.stroke(this);

        return this;
    },

    //  TRANSFORM

    save: function ()
    {
        this.commandBuffer.push(
            Commands.SAVE
        );

        return this;
    },

    restore: function ()
    {
        this.commandBuffer.push(
            Commands.RESTORE
        );

        return this;
    },

    translate: function (x, y)
    {
        this.commandBuffer.push(
            Commands.TRANSLATE,
            x, y
        );

        return this;
    },

    scale: function (x, y)
    {
        this.commandBuffer.push(
            Commands.SCALE,
            x, y
        );

        return this;
    },

    rotate: function (radian)
    {
        this.commandBuffer.push(
            Commands.ROTATE,
            radian
        );

        return this;
    },

    clear: function ()
    {
        this.commandBuffer.length = 0;

        if (this.defaultFillColor > -1)
        {
            this.fillStyle(this.defaultFillColor, this.defaultFillAlpha);
        }

        if (this.defaultStrokeColor > -1)
        {
            this.lineStyle(this.defaultStrokeWidth, this.defaultStrokeColor, this.defaultStrokeAlpha);
        }

        return this;
    },

    //  If key is a string it'll generate a new texture using it and add it into the
    //  Texture Manager (assuming no key conflict happens).
    //
    //  If key is a Canvas it will draw the texture to that canvas context. Note that it will NOT
    //  automatically upload it to the GPU in WebGL mode.

    generateTexture: function (key, width, height)
    {
        var sys = this.scene.sys;

        if (width === undefined) { width = sys.game.config.width; }
        if (height === undefined) { height = sys.game.config.height; }

        Graphics.TargetCamera.setViewport(0, 0, width, height);
        Graphics.TargetCamera.scrollX = this.x;
        Graphics.TargetCamera.scrollY = this.y;

        var texture;
        var ctx;

        if (typeof key === 'string')
        {
            if (sys.textures.exists(key))
            {
                //  Key is a string, it DOES exist in the Texture Manager AND is a canvas, so draw to it

                texture = sys.textures.get(key);

                var src = texture.getSourceImage();

                if (src instanceof HTMLCanvasElement)
                {
                    ctx = src.getContext('2d');
                }
            }
            else
            {
                //  Key is a string and doesn't exist in the Texture Manager, so generate and save it

                texture = sys.textures.createCanvas(key, width, height);

                ctx = texture.getSourceImage().getContext('2d');
            }
        }
        else if (key instanceof HTMLCanvasElement)
        {
            //  Key is a Canvas, so draw to it

            ctx = key.getContext('2d');
        }

        if (ctx)
        {
            this.renderCanvas(sys.game.renderer, this, 0, Graphics.TargetCamera, ctx);

            if (this.gl && texture)
            {
                sys.game.renderer.uploadCanvasToGPU(ctx.canvas, texture.source[0].glTexture, true);
            }
        }

        return this;
    }

});

Graphics.TargetCamera = new Camera(0, 0, 0, 0);

module.exports = Graphics;


var Acceleration = {

    setAccelerationX: function (x)
    {
        this.accel.x = x;

        return this;
    },

    setAccelerationY: function (y)
    {
        this.accel.y = y;

        return this;
    },

    setAcceleration: function (x, y)
    {
        this.accel.x = x;
        this.accel.y = y;

        return this;
    }

};

module.exports = Acceleration;


/**
* Internal function to process the separation of a physics body from a tile.
*
* @private
* @method Phaser.Physics.Arcade#processTileSeparationX
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
* @param {number} x - The x separation amount.
*/
var ProcessTileSeparationX = function (body, x)
{
    if (x < 0)
    {
        body.blocked.left = true;
    }
    else if (x > 0)
    {
        body.blocked.right = true;
    }

    body.position.x -= x;

    if (body.bounce.x === 0)
    {
        body.velocity.x = 0;
    }
    else
    {
        body.velocity.x = -body.velocity.x * body.bounce.x;
    }
};

module.exports = ProcessTileSeparationX;


var Class = require('../../utils/Class');
var CONST = require('../const');
var File = require('../File');
var GetFastValue = require('../../utils/object/GetFastValue');

//  Phaser.Loader.FileTypes.GLSLFile

var GLSLFile = new Class({

    Extends: File,

    initialize:

    function GLSLFile (key, url, path, xhrSettings)
    {
        var fileKey = (typeof key === 'string') ? key : GetFastValue(key, 'key', '');

        var fileConfig = {
            type: 'glsl',
            extension: GetFastValue(key, 'extension', 'glsl'),
            responseType: 'text',
            key: fileKey,
            url: GetFastValue(key, 'file', url),
            path: path,
            xhrSettings: GetFastValue(key, 'xhr', xhrSettings)
        };

        File.call(this, fileConfig);
    },

    onProcess: function (callback)
    {
        this.state = CONST.FILE_PROCESSING;

        this.data = this.xhrLoader.responseText;

        this.onComplete();

        callback(this);
    }

});

GLSLFile.create = function (loader, key, url, xhrSettings)
{
    if (Array.isArray(key))
    {
        for (var i = 0; i < key.length; i++)
        {
            //  If it's an array it has to be an array of Objects, so we get everything out of the 'key' object
            loader.addFile(new GLSLFile(key[i], url, loader.path, xhrSettings));
        }
    }
    else
    {
        loader.addFile(new GLSLFile(key, url, loader.path, xhrSettings));
    }

    //  For method chaining
    return loader;
};

module.exports = GLSLFile;


/**
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
*
* @class SAT
*/

// TODO: true circles and curves

var SAT = {};

module.exports = SAT;

var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');

(function() {

    /**
     * Detect collision between two bodies using the Separating Axis Theorem.
     * @method collides
     * @param {body} bodyA
     * @param {body} bodyB
     * @param {collision} previousCollision
     * @return {collision} collision
     */
    SAT.collides = function(bodyA, bodyB, previousCollision) {
        var overlapAB,
            overlapBA,
            minOverlap,
            collision,
            canReusePrevCol = false;

        if (previousCollision) {
            // estimate total motion
            var parentA = bodyA.parent,
                parentB = bodyB.parent,
                motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed
                       + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed;

            // we may be able to (partially) reuse collision result
            // but only safe if collision was resting
            canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;

            // reuse collision object
            collision = previousCollision;
        } else {
            collision = { collided: false, bodyA: bodyA, bodyB: bodyB };
        }

        if (previousCollision && canReusePrevCol) {
            // if we can reuse the collision result
            // we only need to test the previously found axis
            var axisBodyA = collision.axisBody,
                axisBodyB = axisBodyA === bodyA ? bodyB : bodyA,
                axes = [axisBodyA.axes[previousCollision.axisNumber]];

            minOverlap = _overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes);
            collision.reused = true;

            if (minOverlap.overlap <= 0) {
                collision.collided = false;
                return collision;
            }
        } else {
            // if we can't reuse a result, perform a full SAT test

            overlapAB = _overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes);

            if (overlapAB.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            overlapBA = _overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes);

            if (overlapBA.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            if (overlapAB.overlap < overlapBA.overlap) {
                minOverlap = overlapAB;
                collision.axisBody = bodyA;
            } else {
                minOverlap = overlapBA;
                collision.axisBody = bodyB;
            }

            // important for reuse later
            collision.axisNumber = minOverlap.axisNumber;
        }

        collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
        collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
        collision.collided = true;
        collision.depth = minOverlap.overlap;
        collision.parentA = collision.bodyA.parent;
        collision.parentB = collision.bodyB.parent;

        bodyA = collision.bodyA;
        bodyB = collision.bodyB;

        // ensure normal is facing away from bodyA
        if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
            collision.normal = {
                x: minOverlap.axis.x,
                y: minOverlap.axis.y
            };
        } else {
            collision.normal = {
                x: -minOverlap.axis.x,
                y: -minOverlap.axis.y
            };
        }

        collision.tangent = Vector.perp(collision.normal);

        collision.penetration = collision.penetration || {};
        collision.penetration.x = collision.normal.x * collision.depth;
        collision.penetration.y = collision.normal.y * collision.depth;

        // find support points, there is always either exactly one or two
        var verticesB = _findSupports(bodyA, bodyB, collision.normal),
            supports = [];

        // find the supports from bodyB that are inside bodyA
        if (Vertices.contains(bodyA.vertices, verticesB[0]))
            supports.push(verticesB[0]);

        if (Vertices.contains(bodyA.vertices, verticesB[1]))
            supports.push(verticesB[1]);

        // find the supports from bodyA that are inside bodyB
        if (supports.length < 2) {
            var verticesA = _findSupports(bodyB, bodyA, Vector.neg(collision.normal));

            if (Vertices.contains(bodyB.vertices, verticesA[0]))
                supports.push(verticesA[0]);

            if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
                supports.push(verticesA[1]);
        }

        // account for the edge case of overlapping but no vertex containment
        if (supports.length < 1)
            supports = [verticesB[0]];

        collision.supports = supports;

        return collision;
    };

    /**
     * Find the overlap between two sets of vertices.
     * @method _overlapAxes
     * @private
     * @param {} verticesA
     * @param {} verticesB
     * @param {} axes
     * @return result
     */
    var _overlapAxes = function(verticesA, verticesB, axes) {
        var projectionA = Vector._temp[0],
            projectionB = Vector._temp[1],
            result = { overlap: Number.MAX_VALUE },
            overlap,
            axis;

        for (var i = 0; i < axes.length; i++) {
            axis = axes[i];

            _projectToAxis(projectionA, verticesA, axis);
            _projectToAxis(projectionB, verticesB, axis);

            overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min);

            if (overlap <= 0) {
                result.overlap = overlap;
                return result;
            }

            if (overlap < result.overlap) {
                result.overlap = overlap;
                result.axis = axis;
                result.axisNumber = i;
            }
        }

        return result;
    };

    /**
     * Projects vertices on an axis and returns an interval.
     * @method _projectToAxis
     * @private
     * @param {} projection
     * @param {} vertices
     * @param {} axis
     */
    var _projectToAxis = function(projection, vertices, axis) {
        var min = Vector.dot(vertices[0], axis),
            max = min;

        for (var i = 1; i < vertices.length; i += 1) {
            var dot = Vector.dot(vertices[i], axis);

            if (dot > max) {
                max = dot;
            } else if (dot < min) {
                min = dot;
            }
        }

        projection.min = min;
        projection.max = max;
    };

    /**
     * Finds supporting vertices given two bodies along a given direction using hill-climbing.
     * @method _findSupports
     * @private
     * @param {} bodyA
     * @param {} bodyB
     * @param {} normal
     * @return [vector]
     */
    var _findSupports = function(bodyA, bodyB, normal) {
        var nearestDistance = Number.MAX_VALUE,
            vertexToBody = Vector._temp[0],
            vertices = bodyB.vertices,
            bodyAPosition = bodyA.position,
            distance,
            vertex,
            vertexA,
            vertexB;

        // find closest vertex on bodyB
        for (var i = 0; i < vertices.length; i++) {
            vertex = vertices[i];
            vertexToBody.x = vertex.x - bodyAPosition.x;
            vertexToBody.y = vertex.y - bodyAPosition.y;
            distance = -Vector.dot(normal, vertexToBody);

            if (distance < nearestDistance) {
                nearestDistance = distance;
                vertexA = vertex;
            }
        }

        // find next closest vertex using the two connected to it
        var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1;
        vertex = vertices[prevIndex];
        vertexToBody.x = vertex.x - bodyAPosition.x;
        vertexToBody.y = vertex.y - bodyAPosition.y;
        nearestDistance = -Vector.dot(normal, vertexToBody);
        vertexB = vertex;

        var nextIndex = (vertexA.index + 1) % vertices.length;
        vertex = vertices[nextIndex];
        vertexToBody.x = vertex.x - bodyAPosition.x;
        vertexToBody.y = vertex.y - bodyAPosition.y;
        distance = -Vector.dot(normal, vertexToBody);
        if (distance < nearestDistance) {
            vertexB = vertex;
        }

        return [vertexA, vertexB];
    };

})();


this.setSize(this.layer.tileWidth * this.layer.width, this.layer.tileHeight * this.layer.height);


/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

Phaser.GameObject.SpriteBatch.FACTORY_KEY = 'spriteBatch';

/**
* A SpriteBatch is a really fast version of a Phaser Group built solely for speed.
* Use when you need a lot of sprites or particles all sharing the same texture.
* The speed gains are specifically for WebGL. In Canvas mode you won't see any real difference.
*
* @method Phaser.GameObject.Factory#spriteBatch
* @param {Phaser.Group|null} parent - The parent Group that will hold this Sprite Batch. Set to `undefined` or `null` to add directly to game.world.
* @param {string} [name='group'] - A name for this Sprite Batch. Not used internally but useful for debugging.
* @param {boolean} [addToStage=false] - If set to true this Sprite Batch will be added directly to the Game.Stage instead of the parent.
* @return {Phaser.SpriteBatch} The newly created Sprite Batch.
*/
Phaser.GameObject.SpriteBatch.FACTORY_ADD = function (parent, name, addToStage)
{
    if (parent === undefined) { parent = null; }
    if (name === undefined) { name = 'group'; }
    if (addToStage === undefined) { addToStage = false; }

    return new Phaser.GameObject.SpriteBatch(this.game, parent, name, addToStage);
};

/**
* A SpriteBatch is a really fast version of a Phaser Group built solely for speed.
* Use when you need a lot of sprites or particles all sharing the same texture.
* The speed gains are specifically for WebGL. In Canvas mode you won't see any real difference.
*
* @method Phaser.GameObject.Factory#spriteBatch
* @param {Phaser.Group|null} parent - The parent Group that will hold this Sprite Batch. Set to `undefined` or `null` to add directly to game.world.
* @param {string} [name='group'] - A name for this Sprite Batch. Not used internally but useful for debugging.
* @param {boolean} [addToStage=false] - If set to true this Sprite Batch will be added directly to the Game.Stage instead of the parent.
* @return {Phaser.SpriteBatch} The newly created Sprite Batch.
*/
Phaser.GameObject.SpriteBatch.FACTORY_MAKE = function (parent, name)
{
    if (parent === undefined) { parent = null; }
    if (name === undefined) { name = 'group'; }

    return new Phaser.GameObject.SpriteBatch(this.game, parent, name);
};


var ColorToRGBA = function (color)
{
    var output = {
        r: color >> 16 & 0xFF,
        g: color >> 8 & 0xFF,
        b: color & 0xFF,
        a: 255
    };

    if (color > 16777215)
    {
        output.a = color >>> 24;
    }

    return output;
};

module.exports = ColorToRGBA;


/**
* The `Matter.Resolver` module contains methods for resolving collision pairs.
*
* @class Resolver
*/

var Resolver = {};

module.exports = Resolver;

var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Common = require('../core/Common');
var Bounds = require('../geometry/Bounds');

(function() {

    Resolver._restingThresh = 4;
    Resolver._restingThreshTangent = 6;
    Resolver._positionDampen = 0.9;
    Resolver._positionWarming = 0.8;
    Resolver._frictionNormalMultiplier = 5;

    /**
     * Prepare pairs for position solving.
     * @method preSolvePosition
     * @param {pair[]} pairs
     */
    Resolver.preSolvePosition = function(pairs) {
        var i,
            pair,
            activeCount;

        // find total contacts on each body
        for (i = 0; i < pairs.length; i++) {
            pair = pairs[i];

            if (!pair.isActive)
                continue;

            activeCount = pair.activeContacts.length;
            pair.collision.parentA.totalContacts += activeCount;
            pair.collision.parentB.totalContacts += activeCount;
        }
    };

    /**
     * Find a solution for pair positions.
     * @method solvePosition
     * @param {pair[]} pairs
     * @param {number} timeScale
     */
    Resolver.solvePosition = function(pairs, bodies, timeScale) {
        var i,
            normalX,
            normalY,
            pair,
            collision,
            bodyA,
            bodyB,
            normal,
            separation,
            penetration,
            positionImpulseA,
            positionImpulseB,
            contactShare,
            bodyBtoAX,
            bodyBtoAY,
            positionImpulse,
                impulseCoefficient = timeScale * Resolver._positionDampen;

        for (i = 0; i < bodies.length; i++) {
            var body = bodies[i];
            body.previousPositionImpulse.x = body.positionImpulse.x;
            body.previousPositionImpulse.y = body.positionImpulse.y;
        }

        // find impulses required to resolve penetration
        for (i = 0; i < pairs.length; i++) {
            pair = pairs[i];

            if (!pair.isActive || pair.isSensor)
                continue;

            collision = pair.collision;
            bodyA = collision.parentA;
            bodyB = collision.parentB;
            normal = collision.normal;

            positionImpulseA = bodyA.previousPositionImpulse;
            positionImpulseB = bodyB.previousPositionImpulse;

            penetration = collision.penetration;

            // bodyBtoA = positionImpulseB - positionImpulseA + penetration
            bodyBtoAX = positionImpulseB.x - positionImpulseA.x + penetration.x;
            bodyBtoAY = positionImpulseB.y - positionImpulseA.y + penetration.y;

            normalX = normal.x;
            normalY = normal.y;

            // separation = dot(normal, bodyBtoA)
            separation = normalX * bodyBtoAX + normalY * bodyBtoAY;
            pair.separation = separation;

            positionImpulse = (separation - pair.slop) * impulseCoefficient;

            if (bodyA.isStatic || bodyB.isStatic)
                positionImpulse *= 2;

            if (!(bodyA.isStatic || bodyA.isSleeping)) {
                contactShare = positionImpulse / bodyA.totalContacts;
                bodyA.positionImpulse.x += normalX * contactShare;
                bodyA.positionImpulse.y += normalY * contactShare;
            }

            if (!(bodyB.isStatic || bodyB.isSleeping)) {
                contactShare = positionImpulse / bodyB.totalContacts;
                bodyB.positionImpulse.x -= normalX * contactShare;
                bodyB.positionImpulse.y -= normalY * contactShare;
            }
        }
    };

    /**
     * Apply position resolution.
     * @method postSolvePosition
     * @param {body[]} bodies
     */
    Resolver.postSolvePosition = function(bodies) {
        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            // reset contact count
            body.totalContacts = 0;

            if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
                // update body geometry
                for (var j = 0; j < body.parts.length; j++) {
                    var part = body.parts[j];
                    Vertices.translate(part.vertices, body.positionImpulse);
                    Bounds.update(part.bounds, part.vertices, body.velocity);
                    part.position.x += body.positionImpulse.x;
                    part.position.y += body.positionImpulse.y;
                }

                // move the body without changing velocity
                body.positionPrev.x += body.positionImpulse.x;
                body.positionPrev.y += body.positionImpulse.y;

                if (Vector.dot(body.positionImpulse, body.velocity) < 0) {
                    // reset cached impulse if the body has velocity along it
                    body.positionImpulse.x = 0;
                    body.positionImpulse.y = 0;
                } else {
                    // warm the next iteration
                    body.positionImpulse.x *= Resolver._positionWarming;
                    body.positionImpulse.y *= Resolver._positionWarming;
                }
            }
        }
    };

    /**
     * Prepare pairs for velocity solving.
     * @method preSolveVelocity
     * @param {pair[]} pairs
     */
    Resolver.preSolveVelocity = function(pairs) {
        var i,
            j,
            pair,
            contacts,
            collision,
            bodyA,
            bodyB,
            normal,
            tangent,
            contact,
            contactVertex,
            normalImpulse,
            tangentImpulse,
            offset,
            impulse = Vector._temp[0],
            tempA = Vector._temp[1];

        for (i = 0; i < pairs.length; i++) {
            pair = pairs[i];

            if (!pair.isActive || pair.isSensor)
                continue;

            contacts = pair.activeContacts;
            collision = pair.collision;
            bodyA = collision.parentA;
            bodyB = collision.parentB;
            normal = collision.normal;
            tangent = collision.tangent;

            // resolve each contact
            for (j = 0; j < contacts.length; j++) {
                contact = contacts[j];
                contactVertex = contact.vertex;
                normalImpulse = contact.normalImpulse;
                tangentImpulse = contact.tangentImpulse;

                if (normalImpulse !== 0 || tangentImpulse !== 0) {
                    // total impulse from contact
                    impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
                    impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);

                    // apply impulse from contact
                    if (!(bodyA.isStatic || bodyA.isSleeping)) {
                        offset = Vector.sub(contactVertex, bodyA.position, tempA);
                        bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
                        bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
                        bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia;
                    }

                    if (!(bodyB.isStatic || bodyB.isSleeping)) {
                        offset = Vector.sub(contactVertex, bodyB.position, tempA);
                        bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
                        bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
                        bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia;
                    }
                }
            }
        }
    };

    /**
     * Find a solution for pair velocities.
     * @method solveVelocity
     * @param {pair[]} pairs
     * @param {number} timeScale
     */
    Resolver.solveVelocity = function(pairs, timeScale) {
        var timeScaleSquared = timeScale * timeScale,
            impulse = Vector._temp[0],
            tempA = Vector._temp[1],
            tempB = Vector._temp[2],
            tempC = Vector._temp[3],
            tempD = Vector._temp[4],
            tempE = Vector._temp[5];

        for (var i = 0; i < pairs.length; i++) {
            var pair = pairs[i];

            if (!pair.isActive || pair.isSensor)
                continue;

            var collision = pair.collision,
                bodyA = collision.parentA,
                bodyB = collision.parentB,
                normal = collision.normal,
                tangent = collision.tangent,
                contacts = pair.activeContacts,
                contactShare = 1 / contacts.length;

            // update body velocities
            bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x;
            bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y;
            bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x;
            bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y;
            bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
            bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;

            // resolve each contact
            for (var j = 0; j < contacts.length; j++) {
                var contact = contacts[j],
                    contactVertex = contact.vertex,
                    offsetA = Vector.sub(contactVertex, bodyA.position, tempA),
                    offsetB = Vector.sub(contactVertex, bodyB.position, tempB),
                    velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC),
                    velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD),
                    relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE),
                    normalVelocity = Vector.dot(normal, relativeVelocity);

                var tangentVelocity = Vector.dot(tangent, relativeVelocity),
                    tangentSpeed = Math.abs(tangentVelocity),
                    tangentVelocityDirection = Common.sign(tangentVelocity);

                // raw impulses
                var normalImpulse = (1 + pair.restitution) * normalVelocity,
                    normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier;

                // coulomb friction
                var tangentImpulse = tangentVelocity,
                    maxFriction = Infinity;

                if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) {
                    maxFriction = tangentSpeed;
                    tangentImpulse = Common.clamp(
                        pair.friction * tangentVelocityDirection * timeScaleSquared,
                        -maxFriction, maxFriction
                    );
                }

                // modify impulses accounting for mass, inertia and offset
                var oAcN = Vector.cross(offsetA, normal),
                    oBcN = Vector.cross(offsetB, normal),
                    share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN  + bodyB.inverseInertia * oBcN * oBcN);

                normalImpulse *= share;
                tangentImpulse *= share;

                // handle high velocity and resting collisions separately
                if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) {
                    // high normal velocity so clear cached contact normal impulse
                    contact.normalImpulse = 0;
                } else {
                    // solve resting collision constraints using Erin Catto's method (GDC08)
                    // impulse constraint tends to 0
                    var contactNormalImpulse = contact.normalImpulse;
                    contact.normalImpulse = Math.min(contact.normalImpulse + normalImpulse, 0);
                    normalImpulse = contact.normalImpulse - contactNormalImpulse;
                }

                // handle high velocity and resting collisions separately
                if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) {
                    // high tangent velocity so clear cached contact tangent impulse
                    contact.tangentImpulse = 0;
                } else {
                    // solve resting collision constraints using Erin Catto's method (GDC08)
                    // tangent impulse tends to -tangentSpeed or +tangentSpeed
                    var contactTangentImpulse = contact.tangentImpulse;
                    contact.tangentImpulse = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction);
                    tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
                }

                // total impulse from contact
                impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
                impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);

                // apply impulse from contact
                if (!(bodyA.isStatic || bodyA.isSleeping)) {
                    bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
                    bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
                    bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia;
                }

                if (!(bodyB.isStatic || bodyB.isSleeping)) {
                    bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
                    bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
                    bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia;
                }
            }
        }
    };

})();


keep keep keep replace keep keep keep keep keep

var Class = require('../../../utils/Class');
var GameObject = require('../../GameObject');
var Components = require('../../components');
var CONST = require('../../../renderer/webgl/renderers/tilemaprenderer/const');
var StaticTilemapLayerRender = require('./StaticTilemapLayerRender');
var TilemapComponents = require('../components');

var StaticTilemapLayer = new Class({

    Extends: GameObject,

    Mixins: [
        Components.Alpha,
        Components.BlendMode,
        Components.Flip,
        Components.GetBounds,
        Components.Origin,
        Components.RenderTarget,
        Components.ScaleMode,
        Components.Size,
        Components.Texture,
        Components.Transform,
        Components.Visible,
        Components.ScrollFactor,
        StaticTilemapLayerRender
    ],

    initialize:

    /**
     * A StaticTilemapLayer is a game object that renders LayerData from a Tilemap. A
     * StaticTilemapLayer can only render tiles from a single tileset.
     *
     * A StaticTilemapLayer is optimized for speed over flexibility. You cannot apply per-tile
     * effects like tint or alpha. You cannot change the tiles in a StaticTilemapLayer. Use this
     * over a DynamicTilemapLayer when you don't need either of those features.
     *
     * @class StaticTilemapLayer
     * @constructor
     *
     * @param {Scene} scene - [description]
     * @param {Tilemap} tilemap - The Tilemap this layer is a part of.
     * @param {integer} layerIndex - The index of the LayerData associated with this layer.
     * @param {Tileset} tileset - The tileset used to render the tiles in this layer.
     * @param {number} [x=0] - The world x position where the top left of this layer will be placed.
     * @param {number} [y=0] - The world y position where the top left of this layer will be placed.
     */
    function StaticTilemapLayer (scene, tilemap, layerIndex, tileset, x, y)
    {
        GameObject.call(this, scene, 'StaticTilemapLayer');

        /**
         * Used internally by physics system to perform fast type checks.
         * @property {boolean} isTilemap
         * @readonly
         */
        this.isTilemap = true;

        /**
         * The Tilemap that this layer is a part of.
         * @property {Tilemap} map
         */
        this.map = tilemap;

        /**
         * The index of the LayerData associated with this layer.
         * @property {integer} layerIndex
         */
        this.layerIndex = layerIndex;

        /**
         * The LayerData associated with this layer. LayerData can only be associated with one
         * tilemap layer.
         * @property {LayerData} layerIndex
         */
        this.layer = tilemap.layers[layerIndex];
        this.layer.tilemapLayer = this; // Link the LayerData with this static tilemap layer

        /**
         * The Tileset associated with this layer. A tilemap layer can only render from one Tileset.
         * @property {Tileset} tileset
         */
        this.tileset = tileset;

        /**
         * Used internally with the canvas render. This holds the tiles that are visible within the
         * camera.
         * @property {Tileset} culledTiles
         */
        this.culledTiles = [];

        this.vbo = null;
        this.gl = scene.sys.game.renderer.gl ? scene.sys.game.renderer.gl : null;
        this.tilemapRenderer = scene.sys.game.renderer.tilemapRenderer ? scene.sys.game.renderer.tilemapRenderer : null;
        this.resourceManager = this.gl ? scene.sys.game.renderer.resourceManager : null;
        this.bufferData = null;

        this.dirty = true;
        this.vertexCount = 0;

        this.setAlpha(this.layer.alpha);
        this.setTexture(tileset.image.key);
        this.setPosition(x, y);
        this.setSizeToFrame();
        this.setOrigin();
        this.setSize(this.layer.tileWidth * this.layer.width, this.layer.tileHeight * this.layer.height);

        scene.sys.game.renderer.addContextRestoredCallback(this.contextRestore.bind(this));
    },

    /**
     * @return {this}
     */
    contextRestore: function (renderer)
    {
        this.tileTexture = null;
        this.dirty = true;
        this.vbo = null;
        this.gl = renderer.gl;
        this.tilemapRenderer = renderer.tilemapRenderer;
        return this;
    },

    /**
     * Upload the tile data to a VBO.
     *
     * @return {this}
     */
    upload: function (camera)
    {
        var tileset = this.tileset;
        var mapWidth = this.layer.width;
        var mapHeight = this.layer.height;
        var width = this.texture.source[0].width;
        var height = this.texture.source[0].height;
        var mapData = this.layer.data;

        var tile;
        var row;
        var col;
        var texCoords;

        if (this.gl)
        {
            if (this.dirty)
            {
                var gl = this.gl;
                var vbo = this.vbo;
                var bufferData = this.bufferData;
                var bufferF32;
                var voffset = 0;
                var vertexCount = 0;

                if (this.vbo === null)
                {
                    vbo = this.resourceManager.createBuffer(gl.ARRAY_BUFFER, (4 * 6 * (mapWidth * mapHeight)) * 4, gl.STATIC_DRAW);

                    vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_position'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 0);
                    vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_tex_coord'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 8);

                    bufferData = this.bufferData = new ArrayBuffer((4 * 6 * (mapWidth * mapHeight)) * 4);

                    this.vbo = vbo;

                    vbo.bind();
                }

                bufferF32 = new Float32Array(bufferData);

                for (row = 0; row < mapHeight; ++row)
                {
                    for (col = 0; col < mapWidth; ++col)
                    {
                        tile = mapData[row][col];
                        if (tile === null || tile.index === -1) { continue; }

                        var tx = tile.pixelX;
                        var ty = tile.pixelY;
                        var txw = tx + tile.width;
                        var tyh = ty + tile.height;

                        texCoords = tileset.getTileTextureCoordinates(tile.index);
                        if (texCoords === null) { continue; }

                        // Inset UV coordinates by 0.5px to prevent tile bleeding
                        var u0 = (texCoords.x + 0.5) / width;
                        var v0 = (texCoords.y + 0.5) / height;
                        var u1 = (texCoords.x + tile.width - 0.5) / width;
                        var v1 = (texCoords.y + tile.height - 0.5) / height;

                        var tx0 = tx;
                        var ty0 = ty;
                        var tx1 = tx;
                        var ty1 = tyh;
                        var tx2 = txw;
                        var ty2 = tyh;
                        var tx3 = txw;
                        var ty3 = ty;

                        bufferF32[voffset + 0] = tx0;
                        bufferF32[voffset + 1] = ty0;
                        bufferF32[voffset + 2] = u0;
                        bufferF32[voffset + 3] = v0;

                        bufferF32[voffset + 4] = tx1;
                        bufferF32[voffset + 5] = ty1;
                        bufferF32[voffset + 6] = u0;
                        bufferF32[voffset + 7] = v1;

                        bufferF32[voffset + 8] = tx2;
                        bufferF32[voffset + 9] = ty2;
                        bufferF32[voffset + 10] = u1;
                        bufferF32[voffset + 11] = v1;

                        bufferF32[voffset + 12] = tx0;
                        bufferF32[voffset + 13] = ty0;
                        bufferF32[voffset + 14] = u0;
                        bufferF32[voffset + 15] = v0;

                        bufferF32[voffset + 16] = tx2;
                        bufferF32[voffset + 17] = ty2;
                        bufferF32[voffset + 18] = u1;
                        bufferF32[voffset + 19] = v1;

                        bufferF32[voffset + 20] = tx3;
                        bufferF32[voffset + 21] = ty3;
                        bufferF32[voffset + 22] = u1;
                        bufferF32[voffset + 23] = v0;

                        voffset += 24;
                        vertexCount += 6;
                    }
                }

                this.vertexCount = vertexCount;

                vbo.updateResource(bufferData, 0);

                this.dirty = false;
            }

            var renderer = this.tilemapRenderer;

            renderer.shader.setConstantFloat2(renderer.scrollLocation, camera.scrollX, camera.scrollY);
            renderer.shader.setConstantFloat2(renderer.scrollFactorLocation, this.scrollFactorX, this.scrollFactorY);
            renderer.shader.setConstantFloat2(renderer.tilemapPositionLocation, this.x, this.y);

            var cmat = camera.matrix.matrix;

            renderer.shader.setConstantMatrix3x3(
                renderer.cameraTransformLocation,
                [
                    cmat[0], cmat[1], 0.0,
                    cmat[2], cmat[3], 0.0,
                    cmat[4], cmat[5], 1.0
                ]
            );
        }

        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    calculateFacesWithin: function (tileX, tileY, width, height)
    {
        TilemapComponents.CalculateFacesWithin(tileX, tileY, width, height, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Sprite[]}
     */
    createFromTiles: function (indexes, replacements, spriteConfig, scene, camera)
    {
        return TilemapComponents.CreateFromTiles(indexes, replacements, spriteConfig, scene, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    cull: function (camera)
    {
        return TilemapComponents.CullTiles(this.layer, camera, this.culledTiles);
    },

    /**
    * Destroys this StaticTilemapLayer and removes its link to the associated LayerData.
    */
    destroy: function ()
    {
        // Uninstall this layer only if it is still installed on the LayerData object
        if (this.layer.tilemapLayer === this)
        {
            this.layer.tilemapLayer = undefined;
        }
        this.map = undefined;
        this.layer = undefined;
        this.tileset = undefined;
        GameObject.prototype.destroy.call(this);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    findByIndex: function (findIndex, skip, reverse)
    {
        return TilemapComponents.FindByIndex(findIndex, skip, reverse, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile|null}
     */
    findTile: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.FindTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    filterTiles: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.FilterTiles(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    forEachTile: function (callback, context, tileX, tileY, width, height, filteringOptions)
    {
        TilemapComponents.ForEachTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    getTileAt: function (tileX, tileY, nonNull)
    {
        return TilemapComponents.GetTileAt(tileX, tileY, nonNull, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile}
     */
    getTileAtWorldXY: function (worldX, worldY, nonNull, camera)
    {
        return TilemapComponents.GetTileAtWorldXY(worldX, worldY, nonNull, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithin: function (tileX, tileY, width, height, filteringOptions)
    {
        return TilemapComponents.GetTilesWithin(tileX, tileY, width, height, filteringOptions, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithinWorldXY: function (worldX, worldY, width, height, filteringOptions, camera)
    {
        return TilemapComponents.GetTilesWithinWorldXY(worldX, worldY, width, height, filteringOptions, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Tile[]}
     */
    getTilesWithinShape: function (shape, filteringOptions, camera)
    {
        return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {boolean}
     */
    hasTileAt: function (tileX, tileY)
    {
        return TilemapComponents.HasTileAt(tileX, tileY, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {boolean}
     */
    hasTileAtWorldXY: function (worldX, worldY, camera)
    {
        return TilemapComponents.HasTileAtWorldXY(worldX, worldY, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    renderDebug: function (graphics, styleConfig)
    {
        TilemapComponents.RenderDebug(graphics, styleConfig, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollision: function (indexes, collides, recalculateFaces)
    {
        TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollisionBetween: function (start, stop, collides, recalculateFaces)
    {
        TilemapComponents.SetCollisionBetween(start, stop, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setCollisionByExclusion: function (indexes, collides, recalculateFaces)
    {
        TilemapComponents.SetCollisionByExclusion(indexes, collides, recalculateFaces, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setTileIndexCallback: function (indexes, callback, callbackContext)
    {
        TilemapComponents.SetTileIndexCallback(indexes, callback, callbackContext, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {this}
     */
    setTileLocationCallback: function (tileX, tileY, width, height, callback, callbackContext)
    {
        TilemapComponents.SetTileLocationCallback(tileX, tileY, width, height, callback, callbackContext, this.layer);
        return this;
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    tileToWorldX: function (tileX, camera)
    {
        return TilemapComponents.TileToWorldX(tileX, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    tileToWorldY: function (tileY, camera)
    {
        return TilemapComponents.TileToWorldY(tileY, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Vector2}
     */
    tileToWorldXY: function (tileX, tileY, point, camera)
    {
        return TilemapComponents.TileToWorldXY(tileX, tileY, point, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    worldToTileX: function (worldX, snapToFloor, camera)
    {
        return TilemapComponents.WorldToTileX(worldX, snapToFloor, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {number}
     */
    worldToTileY: function (worldY, snapToFloor, camera)
    {
        return TilemapComponents.WorldToTileY(worldY, snapToFloor, camera, this.layer);
    },

    /**
     * See component documentation.
     *
     * @return {Vector2}
     */
    worldToTileXY: function (worldX, worldY, snapToFloor, point, camera)
    {
        return TilemapComponents.WorldToTileXY(worldX, worldY, snapToFloor, point, camera, this.layer);
    }

});

module.exports = StaticTilemapLayer;


var MathSmootherStep = require('../math/SmootherStep');

/**
 * [description]
 *
 * @function Phaser.Actions.SmootherStep
 * @since 3.0.0
 *
 * @param {array} items - An array of Game Objects. The contents of this array are updated by this Action.
 * @param {string} property - [description]
 * @param {number} min - [description]
 * @param {number} max - [description]
 * @param {number} inc - [description]
 *
 * @return {array} The array of Game Objects that was passed to this Action.
 */
var SmootherStep = function (items, property, min, max, inc)
{
    if (inc === undefined) { inc = false; }

    var step = Math.abs(max - min) / items.length;
    var i;

    if (inc)
    {
        for (i = 0; i < items.length; i++)
        {
            items[i][property] += MathSmootherStep(i * step, min, max);
        }
    }
    else
    {
        for (i = 0; i < items.length; i++)
        {
            items[i][property] = MathSmootherStep(i * step, min, max);
        }
    }

    return items;
};

module.exports = SmootherStep;


var DistanceBetween = require('../../../math/distance/DistanceBetween');
var GetOverlapX = require('./GetOverlapX');
var GetOverlapY = require('./GetOverlapY');

var SeparateCircle = function (body1, body2, overlapOnly, bias)
{
    //  Set the bounding box overlap values into the bodies themselves (hence we don't use the return values here)
    GetOverlapX(body1, body2, false, bias);
    GetOverlapY(body1, body2, false, bias);

    var dx = body2.center.x - body1.center.x;
    var dy = body2.center.y - body1.center.y;

    var angleCollision = Math.atan2(dy, dx);

    var overlap = 0;

    if (body1.isCircle !== body2.isCircle)
    {
        var rect = {
            x: (body2.isCircle) ? body1.position.x : body2.position.x,
            y: (body2.isCircle) ? body1.position.y : body2.position.y,
            right: (body2.isCircle) ? body1.right : body2.right,
            bottom: (body2.isCircle) ? body1.bottom : body2.bottom
        };

        var circle = {
            x: (body1.isCircle) ? body1.center.x : body2.center.x,
            y: (body1.isCircle) ? body1.center.y : body2.center.y,
            radius: (body1.isCircle) ? body1.halfWidth : body2.halfWidth
        };

        if (circle.y < rect.y)
        {
            if (circle.x < rect.x)
            {
                overlap = DistanceBetween(circle.x, circle.y, rect.x, rect.y) - circle.radius;
            }
            else if (circle.x > rect.right)
            {
                overlap = DistanceBetween(circle.x, circle.y, rect.right, rect.y) - circle.radius;
            }
        }
        else if (circle.y > rect.bottom)
        {
            if (circle.x < rect.x)
            {
                overlap = DistanceBetween(circle.x, circle.y, rect.x, rect.bottom) - circle.radius;
            }
            else if (circle.x > rect.right)
            {
                overlap = DistanceBetween(circle.x, circle.y, rect.right, rect.bottom) - circle.radius;
            }
        }

        overlap *= -1;
    }
    else
    {
        overlap = (body1.halfWidth + body2.halfWidth) - DistanceBetween(body1.center.x, body1.center.y, body2.center.x, body2.center.y);
    }

    //  Can't separate two immovable bodies, or a body with its own custom separation logic
    if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
    {
        if (overlap !== 0 && (body1.onOverlap || body2.onOverlap))
        {
            this.emit('overlap', body1.gameObject, body2.gameObject, body1, body2);
        }

        //  return true if there was some overlap, otherwise false
        return (overlap !== 0);
    }

    // Transform the velocity vector to the coordinate system oriented along the direction of impact.
    // This is done to eliminate the vertical component of the velocity

    var b1vx = body1.velocity.x;
    var b1vy = body1.velocity.y;
    var b1mass = body1.mass;

    var b2vx = body2.velocity.x;
    var b2vy = body2.velocity.y;
    var b2mass = body2.mass;

    var v1 = {
        x: b1vx * Math.cos(angleCollision) + b1vy * Math.sin(angleCollision),
        y: b1vx * Math.sin(angleCollision) - b1vy * Math.cos(angleCollision)
    };

    var v2 = {
        x: b2vx * Math.cos(angleCollision) + b2vy * Math.sin(angleCollision),
        y: b2vx * Math.sin(angleCollision) - b2vy * Math.cos(angleCollision)
    };

    // We expect the new velocity after impact
    var tempVel1 = ((b1mass - b2mass) * v1.x + 2 * b2mass * v2.x) / (b1mass + b2mass);
    var tempVel2 = (2 * b1mass * v1.x + (b2mass - b1mass) * v2.x) / (b1mass + b2mass);

    // We convert the vector to the original coordinate system and multiplied by factor of rebound
    if (!body1.immovable)
    {
        body1.velocity.x = (tempVel1 * Math.cos(angleCollision) - v1.y * Math.sin(angleCollision)) * body1.bounce.x;
        body1.velocity.y = (v1.y * Math.cos(angleCollision) + tempVel1 * Math.sin(angleCollision)) * body1.bounce.y;

        //  Reset local var
        b1vx = body1.velocity.x;
        b1vy = body1.velocity.y;
    }

    if (!body2.immovable)
    {
        body2.velocity.x = (tempVel2 * Math.cos(angleCollision) - v2.y * Math.sin(angleCollision)) * body2.bounce.x;
        body2.velocity.y = (v2.y * Math.cos(angleCollision) + tempVel2 * Math.sin(angleCollision)) * body2.bounce.y;

        //  Reset local var
        b2vx = body2.velocity.x;
        b2vy = body2.velocity.y;
    }

    // When the collision angle is almost perpendicular to the total initial velocity vector
    // (collision on a tangent) vector direction can be determined incorrectly.
    // This code fixes the problem

    if (Math.abs(angleCollision) < Math.PI / 2)
    {
        if ((b1vx > 0) && !body1.immovable && (b2vx > b1vx))
        {
            body1.velocity.x *= -1;
        }
        else if ((b2vx < 0) && !body2.immovable && (b1vx < b2vx))
        {
            body2.velocity.x *= -1;
        }
        else if ((b1vy > 0) && !body1.immovable && (b2vy > b1vy))
        {
            body1.velocity.y *= -1;
        }
        else if ((b2vy < 0) && !body2.immovable && (b1vy < b2vy))
        {
            body2.velocity.y *= -1;
        }
    }
    else if (Math.abs(angleCollision) > Math.PI / 2)
    {
        if ((b1vx < 0) && !body1.immovable && (b2vx < b1vx))
        {
            body1.velocity.x *= -1;
        }
        else if ((b2vx > 0) && !body2.immovable && (b1vx > b2vx))
        {
            body2.velocity.x *= -1;
        }
        else if ((b1vy < 0) && !body1.immovable && (b2vy < b1vy))
        {
            body1.velocity.y *= -1;
        }
        else if ((b2vy > 0) && !body2.immovable && (b1vx > b2vy))
        {
            body2.velocity.y *= -1;
        }
    }

    if (!body1.immovable)
    {
        body1.x += (body1.velocity.x * this.delta) - overlap * Math.cos(angleCollision);
        body1.y += (body1.velocity.y * this.delta) - overlap * Math.sin(angleCollision);
    }

    if (!body2.immovable)
    {
        body2.x += (body2.velocity.x * this.delta) + overlap * Math.cos(angleCollision);
        body2.y += (body2.velocity.y * this.delta) + overlap * Math.sin(angleCollision);
    }

    if (body1.onCollide || body2.onCollide)
    {
        this.emit('collide', body1.gameObject, body2.gameObject, body1, body2);
    }

    return true;
};

module.exports = SeparateCircle;