/**
* The `Matter.Vector` module contains methods for creating and manipulating vectors.
* Vectors are the basis of all the geometry related operations in the engine.
* A `Matter.Vector` object is of the form `{ x: 0, y: 0 }`.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
*
* @class Vector
*/

// TODO: consider params for reusing vector objects

var Vector = {};

module.exports = Vector;

(function() {

    /**
     * Creates a new vector.
     * @method create
     * @param {number} x
     * @param {number} y
     * @return {vector} A new vector
     */
    Vector.create = function(x, y) {
        return { x: x || 0, y: y || 0 };
    };

    /**
     * Returns a new vector with `x` and `y` copied from the given `vector`.
     * @method clone
     * @param {vector} vector
     * @return {vector} A new cloned vector
     */
    Vector.clone = function(vector) {
        return { x: vector.x, y: vector.y };
    };

    /**
     * Returns the magnitude (length) of a vector.
     * @method magnitude
     * @param {vector} vector
     * @return {number} The magnitude of the vector
     */
    Vector.magnitude = function(vector) {
        return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y));
    };

    /**
     * Returns the magnitude (length) of a vector (therefore saving a `sqrt` operation).
     * @method magnitudeSquared
     * @param {vector} vector
     * @return {number} The squared magnitude of the vector
     */
    Vector.magnitudeSquared = function(vector) {
        return (vector.x * vector.x) + (vector.y * vector.y);
    };

    /**
     * Rotates the vector about (0, 0) by specified angle.
     * @method rotate
     * @param {vector} vector
     * @param {number} angle
     * @param {vector} [output]
     * @return {vector} The vector rotated about (0, 0)
     */
    Vector.rotate = function(vector, angle, output) {
        var cos = Math.cos(angle), sin = Math.sin(angle);
        if (!output) output = {};
        var x = vector.x * cos - vector.y * sin;
        output.y = vector.x * sin + vector.y * cos;
        output.x = x;
        return output;
    };

    /**
     * Rotates the vector about a specified point by specified angle.
     * @method rotateAbout
     * @param {vector} vector
     * @param {number} angle
     * @param {vector} point
     * @param {vector} [output]
     * @return {vector} A new vector rotated about the point
     */
    Vector.rotateAbout = function(vector, angle, point, output) {
        var cos = Math.cos(angle), sin = Math.sin(angle);
        if (!output) output = {};
        var x = point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin);
        output.y = point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos);
        output.x = x;
        return output;
    };

    /**
     * Normalises a vector (such that its magnitude is `1`).
     * @method normalise
     * @param {vector} vector
     * @return {vector} A new vector normalised
     */
    Vector.normalise = function(vector) {
        var magnitude = Vector.magnitude(vector);
        if (magnitude === 0)
            return { x: 0, y: 0 };
        return { x: vector.x / magnitude, y: vector.y / magnitude };
    };

    /**
     * Returns the dot-product of two vectors.
     * @method dot
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @return {number} The dot product of the two vectors
     */
    Vector.dot = function(vectorA, vectorB) {
        return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y);
    };

    /**
     * Returns the cross-product of two vectors.
     * @method cross
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @return {number} The cross product of the two vectors
     */
    Vector.cross = function(vectorA, vectorB) {
        return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x);
    };

    /**
     * Returns the cross-product of three vectors.
     * @method cross3
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @param {vector} vectorC
     * @return {number} The cross product of the three vectors
     */
    Vector.cross3 = function(vectorA, vectorB, vectorC) {
        return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x);
    };

    /**
     * Adds the two vectors.
     * @method add
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @param {vector} [output]
     * @return {vector} A new vector of vectorA and vectorB added
     */
    Vector.add = function(vectorA, vectorB, output) {
        if (!output) output = {};
        output.x = vectorA.x + vectorB.x;
        output.y = vectorA.y + vectorB.y;
        return output;
    };

    /**
     * Subtracts the two vectors.
     * @method sub
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @param {vector} [output]
     * @return {vector} A new vector of vectorA and vectorB subtracted
     */
    Vector.sub = function(vectorA, vectorB, output) {
        if (!output) output = {};
        output.x = vectorA.x - vectorB.x;
        output.y = vectorA.y - vectorB.y;
        return output;
    };

    /**
     * Multiplies a vector and a scalar.
     * @method mult
     * @param {vector} vector
     * @param {number} scalar
     * @return {vector} A new vector multiplied by scalar
     */
    Vector.mult = function(vector, scalar) {
        return { x: vector.x * scalar, y: vector.y * scalar };
    };

    /**
     * Divides a vector and a scalar.
     * @method div
     * @param {vector} vector
     * @param {number} scalar
     * @return {vector} A new vector divided by scalar
     */
    Vector.div = function(vector, scalar) {
        return { x: vector.x / scalar, y: vector.y / scalar };
    };

    /**
     * Returns the perpendicular vector. Set `negate` to true for the perpendicular in the opposite direction.
     * @method perp
     * @param {vector} vector
     * @param {bool} [negate=false]
     * @return {vector} The perpendicular vector
     */
    Vector.perp = function(vector, negate) {
        negate = negate === true ? -1 : 1;
        return { x: negate * -vector.y, y: negate * vector.x };
    };

    /**
     * Negates both components of a vector such that it points in the opposite direction.
     * @method neg
     * @param {vector} vector
     * @return {vector} The negated vector
     */
    Vector.neg = function(vector) {
        return { x: -vector.x, y: -vector.y };
    };

    /**
     * Returns the angle between the vector `vectorB - vectorA` and the x-axis in radians.
     * @method angle
     * @param {vector} vectorA
     * @param {vector} vectorB
     * @return {number} The angle in radians
     */
    Vector.angle = function(vectorA, vectorB) {
        return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x);
    };

    /**
     * Temporary vector pool (not thread-safe).
     * @property _temp
     * @type {vector[]}
     * @private
     */
    Vector._temp = [
        Vector.create(), Vector.create(),
        Vector.create(), Vector.create(),
        Vector.create(), Vector.create()
    ];

})();


* @return {Phaser.Tilemaps.Tile} The Tile object that was created or added to this map.

var PutTileAtWorldXY = function (tile, worldX, worldY, recalculateFaces, camera, layer)

var point = layer.tilemapLayer.worldToTileXY(worldX, worldY, true, undefined, camera, layer);

return PutTileAt(tile, tileX, tileY, recalculateFaces, layer);

keep keep keep keep replace replace replace replace keep keep keep

layer.tilemapLayer.worldToTileXY(worldX, worldY, true, point, camera, layer);

return PutTileAt(tile, point.x, point.y, recalculateFaces, layer);

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Extend = require('../../../utils/object/Extend');

/**
 * Copy properties from tileset to tiles.
 *
 * @function Phaser.Tilemaps.Parsers.Tiled.AssignTileProperties
 * @since 3.0.0
 *
 * @param {Phaser.Tilemaps.MapData} mapData - The Map Data object.
 */
var AssignTileProperties = function (mapData)
{
    var layerData;
    var tile;
    var sid;
    var set;
    var row;

    // go through each of the map data layers
    for (var i = 0; i < mapData.layers.length; i++)
    {
        layerData = mapData.layers[i];

        set = null;

        // rows of tiles
        for (var j = 0; j < layerData.data.length; j++)
        {
            row = layerData.data[j];

            // individual tiles
            for (var k = 0; k < row.length; k++)
            {
                tile = row[k];

                if (tile === null || tile.index < 0)
                {
                    continue;
                }

                // find the relevant tileset
                sid = mapData.tiles[tile.index][2];
                set = mapData.tilesets[sid];

                // Ensure that a tile's size matches its tileset
                tile.width = set.tileWidth;
                tile.height = set.tileHeight;

                // if that tile type has any properties, add them to the tile object
                if (set.tileProperties && set.tileProperties[tile.index - set.firstgid])
                {
                    tile.properties = Extend(
                        tile.properties, set.tileProperties[tile.index - set.firstgid]
                    );
                }
            }
        }
    }
};

module.exports = AssignTileProperties;


* @param {integer} tileY - The y coordinate, in tiles, not pixels.

var PutTilesAt = function (tilesArray, tileX, tileY, recalculateFaces, layer)

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var PutTileAt = require('./PutTileAt');

/**
 * Puts a tile at the given world coordinates (pixels) in the specified layer. You can pass in either
 * an index or a Tile object. If you pass in a Tile, all attributes will be copied over to the
 * specified location. If you pass in an index, only the index at the specified location will be
 * changed. Collision information will be recalculated at the specified location.
 *
 * @function Phaser.Tilemaps.Components.PutTileAtWorldXY
 * @since 3.0.0
 *
 * @param {(integer|Phaser.Tilemaps.Tile)} tile - The index of this tile to set or a Tile object.
 * @param {number} worldX - The x coordinate, in pixels.
 * @param {number} worldY - The y coordinate, in pixels.
 * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated.
 * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values.
 * @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
 *
 * @return {Phaser.Tilemaps.Tile} The Tile object that was created or added to this map.
 */
var PutTileAtWorldXY = function (tile, worldX, worldY, recalculateFaces, camera, layer)
{
    var point = layer.tilemapLayer.worldToTileXY(worldX, worldY, true, undefined, camera, layer);
    var tileX = point.x;
    var tileY = point.y;
    return PutTileAt(tile, tileX, tileY, recalculateFaces, layer);
};

module.exports = PutTileAtWorldXY;


#if defined(USE_VCOLOR_RGB) || defined(USE_VCOLOR_RGBA)
    v_Color = a_Color;
#endif


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Rope = require('./Rope');
var GameObjectFactory = require('../GameObjectFactory');

/**
 * Creates a new Rope Game Object and adds it to the Scene.
 *
 * Note: This method will only be available if the Rope Game Object and WebGL support have been built into Phaser.
 *
 * @method Phaser.GameObjects.GameObjectFactory#rope
 * @webglOnly
 * @since 3.23.0
 *
 * @param {number} x - The horizontal position of this Game Object in the world.
 * @param {number} y - The vertical position of this Game Object in the world.
 * @param {(string|Phaser.Textures.Texture)} texture - The key, or instance of the Texture this Game Object will use to render with, as stored in the Texture Manager.
 * @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
 * @param {Phaser.Types.Math.Vector2Like[]} [points] - An array containing the vertices data for this Rope. If none is provided a simple quad is created. See `setPoints` to set this post-creation.
 * @param {boolean} [horizontal=true] - Should the vertices of this Rope be aligned horizontally (`true`), or vertically (`false`)?
 * @param {number[]} [colors] - An optional array containing the color data for this Rope. You should provide one color value per pair of vertices.
 * @param {number[]} [alphas] - An optional array containing the alpha data for this Rope. You should provide one alpha value per pair of vertices.
 *
 * @return {Phaser.GameObjects.Rope} The Game Object that was created.
 */
if (typeof WEBGL_RENDERER)
{
    GameObjectFactory.register('rope', function (x, y, texture, frame, points, horizontal, colors, alphas)
    {
        return this.displayList.add(new Rope(this.scene, x, y, texture, frame, points, horizontal, colors, alphas));
    });
}


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * The Scene Systems Pause Event.
 *
 * This event is dispatched by a Scene when it is paused, either directly via the `pause` method, or as an
 * action from another Scene.
 *
 * Listen to it from a Scene using `this.scene.events.on('pause', listener)`.
 *
 * @event Phaser.Scenes.Events#PAUSE
 * @since 3.0.0
 *
 * @param {Phaser.Scenes.Systems} sys - A reference to the Scene Systems class of the Scene that emitted this event.
 * @param {any} [data] - An optional data object that was passed to this Scene when it was paused.
 */
module.exports = 'pause';


if (!Array.isArray(tilesArray)) { return null; }

if (recalculateFaces === undefined) { recalculateFaces = true; }

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var RemoveTileAt = require('./RemoveTileAt');

/**
 * Removes the tile at the given world coordinates in the specified layer and updates the layer's
 * collision information.
 *
 * @function Phaser.Tilemaps.Components.RemoveTileAtWorldXY
 * @since 3.0.0
 *
 * @param {number} worldX - The x coordinate, in pixels.
 * @param {number} worldY - The y coordinate, in pixels.
 * @param {boolean} [replaceWithNull=true] - If true, this will replace the tile at the specified location with null instead of a Tile with an index of -1.
 * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated.
 * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values.
 * @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
 *
 * @return {Phaser.Tilemaps.Tile} The Tile object that was removed.
 */
var RemoveTileAtWorldXY = function (worldX, worldY, replaceWithNull, recalculateFaces, camera, layer)
{
    var point = layer.tilemapLayer.worldToTileXY(worldX, worldY, true, undefined, camera, layer);
    var tileX = point.x;
    var tileY = point.y;
    return RemoveTileAt(tileX, tileY, replaceWithNull, recalculateFaces, layer);
};

module.exports = RemoveTileAtWorldXY;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var RotateMatrix = require('./RotateMatrix');

/**
 * Rotates the array matrix to the left (or 90 degrees)
 *
 * A matrix is a two-dimensional array (array of arrays), where all sub-arrays (rows)
 * have the same length. There must be at least two rows. This is an example matrix:
 *
 * ```
 * [
 *    [ 1, 1, 1, 1, 1, 1 ],
 *    [ 2, 0, 0, 0, 0, 4 ],
 *    [ 2, 0, 1, 2, 0, 4 ],
 *    [ 2, 0, 3, 4, 0, 4 ],
 *    [ 2, 0, 0, 0, 0, 4 ],
 *    [ 3, 3, 3, 3, 3, 3 ]
 * ]
 * ```
 *
 * @function Phaser.Utils.Array.Matrix.RotateLeft
 * @since 3.0.0
 *
 * @generic T
 * @genericUse {T[][]} - [matrix,$return]
 *
 * @param {T[][]} [matrix] - The array to rotate.
 *
 * @return {T[][]} The rotated matrix array. The source matrix should be discard for the returned matrix.
 */
var RotateLeft = function (matrix)
{
    return RotateMatrix(matrix, 90);
};

module.exports = RotateLeft;


/**
 * @typedef {object} Phaser.Types.GameObjects.Particles.RandomZoneSource
 * @since 3.0.0
 *
 * @property {Phaser.Types.GameObjects.Particles.RandomZoneSourceCallback} getRandomPoint - A function modifying its point argument.
 *
 * @see Phaser.Geom.Circle
 * @see Phaser.Geom.Ellipse
 * @see Phaser.Geom.Line
 * @see Phaser.Geom.Polygon
 * @see Phaser.Geom.Rectangle
 * @see Phaser.Geom.Triangle
 */


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var GetBottom = require('../../bounds/GetBottom');
var GetRight = require('../../bounds/GetRight');
var SetBottom = require('../../bounds/SetBottom');
var SetLeft = require('../../bounds/SetLeft');

/**
 * Takes given Game Object and aligns it so that it is positioned next to the right bottom position of the other.
 *
 * @function Phaser.Display.Align.To.RightBottom
 * @since 3.0.0
 *
 * @generic {Phaser.GameObjects.GameObject} G - [gameObject,$return]
 *
 * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object that will be positioned.
 * @param {Phaser.GameObjects.GameObject} alignTo - The Game Object to base the alignment position on.
 * @param {number} [offsetX=0] - Optional horizontal offset from the position.
 * @param {number} [offsetY=0] - Optional vertical offset from the position.
 *
 * @return {Phaser.GameObjects.GameObject} The Game Object that was aligned.
 */
var RightBottom = function (gameObject, alignTo, offsetX, offsetY)
{
    if (offsetX === undefined) { offsetX = 0; }
    if (offsetY === undefined) { offsetY = 0; }

    SetLeft(gameObject, GetRight(alignTo) + offsetX);
    SetBottom(gameObject, GetBottom(alignTo) + offsetY);

    return gameObject;
};

module.exports = RightBottom;


// Force the input array to be a 2D array

if (!Array.isArray(tilesArray))
{
return null;
}


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Perimeter = require('./Perimeter');
var Point = require('../point/Point');

/**
 * Calculates the coordinates of a point at a certain `position` on the Rectangle's perimeter.
 *
 * The `position` is a fraction between 0 and 1 which defines how far into the perimeter the point is.
 *
 * A value of 0 or 1 returns the point at the top left corner of the rectangle, while a value of 0.5 returns the point at the bottom right corner of the rectangle. Values between 0 and 0.5 are on the top or the right side and values between 0.5 and 1 are on the bottom or the left side.
 *
 * @function Phaser.Geom.Rectangle.GetPoint
 * @since 3.0.0
 *
 * @generic {Phaser.Geom.Point} O - [out,$return]
 *
 * @param {Phaser.Geom.Rectangle} rectangle - The Rectangle to get the perimeter point from.
 * @param {number} position - The normalized distance into the Rectangle's perimeter to return.
 * @param {(Phaser.Geom.Point|object)} [out] - An object to update with the `x` and `y` coordinates of the point.
 *
 * @return {Phaser.Geom.Point} The updated `output` object, or a new Point if no `output` object was given.
 */
var GetPoint = function (rectangle, position, out)
{
    if (out === undefined) { out = new Point(); }

    if (position <= 0 || position >= 1)
    {
        out.x = rectangle.x;
        out.y = rectangle.y;

        return out;
    }

    var p = Perimeter(rectangle) * position;

    if (position > 0.5)
    {
        p -= (rectangle.width + rectangle.height);

        if (p <= rectangle.width)
        {
            //  Face 3
            out.x = rectangle.right - p;
            out.y = rectangle.bottom;
        }
        else
        {
            //  Face 4
            out.x = rectangle.x;
            out.y = rectangle.bottom - (p - rectangle.width);
        }
    }
    else if (p <= rectangle.width)
    {
        //  Face 1
        out.x = rectangle.x + p;
        out.y = rectangle.y;
    }
    else
    {
        //  Face 2
        out.x = rectangle.right;
        out.y = rectangle.y + (p - rectangle.width);
    }

    return out;
};

module.exports = GetPoint;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Calculates the area of the circle.
 *
 * @function Phaser.Geom.Circle.Area
 * @since 3.0.0
 *
 * @param {Phaser.Geom.Circle} circle - The Circle to get the area of.
 *
 * @return {number} The area of the Circle.
 */
var Area = function (circle)
{
    return (circle.radius > 0) ? Math.PI * circle.radius * circle.radius : 0;
};

module.exports = Area;


/**
 * @callback Phaser.Types.Cameras.Scene2D.CameraZoomCallback
 * @since 3.11.0
 *
 * @param {Phaser.Cameras.Scene2D.Camera} camera - The camera on which the effect is running.
 * @param {number} progress - The progress of the effect. A value between 0 and 1.
 * @param {number} zoom - The Camera's new zoom value.
 */


* @license      {@link https://opensource.org/licenses/MIT|MIT License}

var RemoveTileAt = require('./RemoveTileAt');

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


module.exports = [
    '#define SHADER_NAME PHASER_MULTI_FS',
    '',
    'precision mediump float;',
    '',
    'uniform sampler2D uMainSampler[%count%];',
    '',
    'varying vec2 outTexCoord;',
    'varying float outTexId;',
    'varying float outTintEffect;',
    'varying vec4 outTint;',
    '',
    'void main()',
    '{',
    '    vec4 texture;',
    '',
    '    %forloop%',
    '',
    '    vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
    '',
    '    //  Multiply texture tint',
    '    vec4 color = texture * texel;',
    '',
    '    if (outTintEffect == 1.0)',
    '    {',
    '        //  Solid color + texture alpha',
    '        color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);',
    '    }',
    '',
    '    gl_FragColor = color;',
    '}',
    ''
].join('\n');


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Components = require('../components');
var GameObject = require('../GameObject');
var Line = require('../../geom/line/Line');

/**
 * @classdesc
 * The Shape Game Object is a base class for the various different shapes, such as the Arc, Star or Polygon.
 * You cannot add a Shape directly to your Scene, it is meant as a base for your own custom Shape classes.
 *
 * @class Shape
 * @extends Phaser.GameObjects.GameObject
 * @memberof Phaser.GameObjects
 * @constructor
 * @since 3.13.0
 *
 * @extends Phaser.GameObjects.Components.AlphaSingle
 * @extends Phaser.GameObjects.Components.BlendMode
  * @extends Phaser.GameObjects.Components.Depth
 * @extends Phaser.GameObjects.Components.GetBounds
 * @extends Phaser.GameObjects.Components.Mask
 * @extends Phaser.GameObjects.Components.Origin
 * @extends Phaser.GameObjects.Components.Pipeline
 * @extends Phaser.GameObjects.Components.ScrollFactor
 * @extends Phaser.GameObjects.Components.Transform
 * @extends Phaser.GameObjects.Components.Visible
 *
 * @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time.
 * @param {string} [type] - The internal type of the Shape.
 * @param {any} [data] - The data of the source shape geometry, if any.
 */
var Shape = new Class({

    Extends: GameObject,

    Mixins: [
        Components.AlphaSingle,
        Components.BlendMode,
        Components.Depth,
        Components.GetBounds,
        Components.Mask,
        Components.Origin,
        Components.Pipeline,
        Components.ScrollFactor,
        Components.Transform,
        Components.Visible
    ],

    initialize:

    function Shape (scene, type, data)
    {
        if (type === undefined) { type = 'Shape'; }

        GameObject.call(this, scene, type);

        /**
         * The source Shape data. Typically a geometry object.
         * You should not manipulate this directly.
         *
         * @name Phaser.GameObjects.Shape#geom
         * @type {any}
         * @readonly
         * @since 3.13.0
         */
        this.geom = data;

        /**
         * Holds the polygon path data for filled rendering.
         *
         * @name Phaser.GameObjects.Shape#pathData
         * @type {number[]}
         * @readonly
         * @since 3.13.0
         */
        this.pathData = [];

        /**
         * Holds the earcut polygon path index data for filled rendering.
         *
         * @name Phaser.GameObjects.Shape#pathIndexes
         * @type {integer[]}
         * @readonly
         * @since 3.13.0
         */
        this.pathIndexes = [];

        /**
         * The fill color used by this Shape.
         *
         * @name Phaser.GameObjects.Shape#fillColor
         * @type {number}
         * @since 3.13.0
         */
        this.fillColor = 0xffffff;

        /**
         * The fill alpha value used by this Shape.
         *
         * @name Phaser.GameObjects.Shape#fillAlpha
         * @type {number}
         * @since 3.13.0
         */
        this.fillAlpha = 1;

        /**
         * The stroke color used by this Shape.
         *
         * @name Phaser.GameObjects.Shape#strokeColor
         * @type {number}
         * @since 3.13.0
         */
        this.strokeColor = 0xffffff;

        /**
         * The stroke alpha value used by this Shape.
         *
         * @name Phaser.GameObjects.Shape#strokeAlpha
         * @type {number}
         * @since 3.13.0
         */
        this.strokeAlpha = 1;

        /**
         * The stroke line width used by this Shape.
         *
         * @name Phaser.GameObjects.Shape#lineWidth
         * @type {number}
         * @since 3.13.0
         */
        this.lineWidth = 1;

        /**
         * Controls if this Shape is filled or not.
         * Note that some Shapes do not support being filled (such as Line shapes)
         *
         * @name Phaser.GameObjects.Shape#isFilled
         * @type {boolean}
         * @since 3.13.0
         */
        this.isFilled = false;

        /**
         * Controls if this Shape is stroked or not.
         * Note that some Shapes do not support being stroked (such as Iso Box shapes)
         *
         * @name Phaser.GameObjects.Shape#isStroked
         * @type {boolean}
         * @since 3.13.0
         */
        this.isStroked = false;

        /**
         * Controls if this Shape path is closed during rendering when stroked.
         * Note that some Shapes are always closed when stroked (such as Ellipse shapes)
         *
         * @name Phaser.GameObjects.Shape#closePath
         * @type {boolean}
         * @since 3.13.0
         */
        this.closePath = true;

        /**
         * Private internal value.
         * A Line used when parsing internal path data to avoid constant object re-creation.
         *
         * @name Phaser.GameObjects.Shape#_tempLine
         * @type {Phaser.Geom.Line}
         * @private
         * @since 3.13.0
         */
        this._tempLine = new Line();

        /**
         * The native (un-scaled) width of this Game Object.
         *
         * Changing this value will not change the size that the Game Object is rendered in-game.
         * For that you need to either set the scale of the Game Object (`setScale`) or use
         * the `displayWidth` property.
         *
         * @name Phaser.GameObjects.Shape#width
         * @type {number}
         * @since 3.13.0
         */
        this.width = 0;

        /**
         * The native (un-scaled) height of this Game Object.
         *
         * Changing this value will not change the size that the Game Object is rendered in-game.
         * For that you need to either set the scale of the Game Object (`setScale`) or use
         * the `displayHeight` property.
         *
         * @name Phaser.GameObjects.Shape#height
         * @type {number}
         * @since 3.0.0
         */
        this.height = 0;

        this.initPipeline();
    },

    /**
     * Sets the fill color and alpha for this Shape.
     *
     * If you wish for the Shape to not be filled then call this method with no arguments, or just set `isFilled` to `false`.
     *
     * Note that some Shapes do not support fill colors, such as the Line shape.
     *
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Shape#setFillStyle
     * @since 3.13.0
     *
     * @param {number} [color] - The color used to fill this shape. If not provided the Shape will not be filled.
     * @param {number} [alpha=1] - The alpha value used when filling this shape, if a fill color is given.
     *
     * @return {this} This Game Object instance.
     */
    setFillStyle: function (color, alpha)
    {
        if (alpha === undefined) { alpha = 1; }

        if (color === undefined)
        {
            this.isFilled = false;
        }
        else
        {
            this.fillColor = color;
            this.fillAlpha = alpha;
            this.isFilled = true;
        }

        return this;
    },

    /**
     * Sets the stroke color and alpha for this Shape.
     *
     * If you wish for the Shape to not be stroked then call this method with no arguments, or just set `isStroked` to `false`.
     *
     * Note that some Shapes do not support being stroked, such as the Iso Box shape.
     *
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Shape#setStrokeStyle
     * @since 3.13.0
     *
     * @param {number} [lineWidth] - The width of line to stroke with. If not provided or undefined the Shape will not be stroked.
     * @param {number} [color] - The color used to stroke this shape. If not provided the Shape will not be stroked.
     * @param {number} [alpha=1] - The alpha value used when stroking this shape, if a stroke color is given.
     *
     * @return {this} This Game Object instance.
     */
    setStrokeStyle: function (lineWidth, color, alpha)
    {
        if (alpha === undefined) { alpha = 1; }

        if (lineWidth === undefined)
        {
            this.isStroked = false;
        }
        else
        {
            this.lineWidth = lineWidth;
            this.strokeColor = color;
            this.strokeAlpha = alpha;
            this.isStroked = true;
        }

        return this;
    },

    /**
     * Sets if this Shape path is closed during rendering when stroked.
     * Note that some Shapes are always closed when stroked (such as Ellipse shapes)
     *
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Shape#setClosePath
     * @since 3.13.0
     *
     * @param {boolean} value - Set to `true` if the Shape should be closed when stroked, otherwise `false`.
     *
     * @return {this} This Game Object instance.
     */
    setClosePath: function (value)
    {
        this.closePath = value;

        return this;
    },

    /**
     * Sets the internal size of this Game Object, as used for frame or physics body creation.
     *
     * This will not change the size that the Game Object is rendered in-game.
     * For that you need to either set the scale of the Game Object (`setScale`) or call the
     * `setDisplaySize` method, which is the same thing as changing the scale but allows you
     * to do so by giving pixel values.
     *
     * If you have enabled this Game Object for input, changing the size will _not_ change the
     * size of the hit area. To do this you should adjust the `input.hitArea` object directly.
     *
     * @method Phaser.GameObjects.Shape#setSize
     * @private
     * @since 3.13.0
     *
     * @param {number} width - The width of this Game Object.
     * @param {number} height - The height of this Game Object.
     *
     * @return {this} This Game Object instance.
     */
    setSize: function (width, height)
    {
        this.width = width;
        this.height = height;

        return this;
    },

    /**
     * Internal destroy handler, called as part of the destroy process.
     *
     * @method Phaser.GameObjects.Shape#preDestroy
     * @protected
     * @since 3.13.0
     */
    preDestroy: function ()
    {
        this.geom = null;
        this._tempLine = null;
        this.pathData = [];
        this.pathIndexes = [];
    },

    /**
     * The displayed width of this Game Object.
     *
     * This value takes into account the scale factor.
     *
     * Setting this value will adjust the Game Object's scale property.
     *
     * @name Phaser.GameObjects.Shape#displayWidth
     * @type {number}
     * @since 3.13.0
     */
    displayWidth: {

        get: function ()
        {
            return this.scaleX * this.width;
        },

        set: function (value)
        {
            this.scaleX = value / this.width;
        }

    },

    /**
     * The displayed height of this Game Object.
     *
     * This value takes into account the scale factor.
     *
     * Setting this value will adjust the Game Object's scale property.
     *
     * @name Phaser.GameObjects.Shape#displayHeight
     * @type {number}
     * @since 3.13.0
     */
    displayHeight: {

        get: function ()
        {
            return this.scaleY * this.height;
        },

        set: function (value)
        {
            this.scaleY = value / this.height;
        }

    }

});

module.exports = Shape;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Moves the given element to the bottom of the array.
 * The array is modified in-place.
 *
 * @function Phaser.Utils.Array.SendToBack
 * @since 3.4.0
 *
 * @param {array} array - The array.
 * @param {*} item - The element to move.
 *
 * @return {*} The element that was moved.
 */
var SendToBack = function (array, item)
{
    var currentIndex = array.indexOf(item);

    if (currentIndex !== -1 && currentIndex > 0)
    {
        array.splice(currentIndex, 1);
        array.unshift(item);
    }

    return item;
};

module.exports = SendToBack;


* Removes the tile at the given world coordinates in the specified layer and updates the layer's


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Renders this Game Object with the Canvas Renderer to the given Camera.
 * The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
 * This method should not be called directly. It is a utility function of the Render module.
 *
 * @method Phaser.GameObjects.Sprite#renderCanvas
 * @since 3.0.0
 * @private
 *
 * @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
 * @param {Phaser.GameObjects.Sprite} src - The Game Object being rendered in this call.
 * @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
 * @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
 */
var SpriteCanvasRenderer = function (renderer, src, camera, parentMatrix)
{
    renderer.batchSprite(src, src.frame, camera, parentMatrix);
};

module.exports = SpriteCanvasRenderer;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');

var BufferAttribute = new Class({

    initialize:

    function BufferAttribute (array, size, normalized)
    {
        /**
         * The array holding data stored in the buffer.
         * @type {TypedArray}
         */
        this.array = array;

        /**
         * The length of vectors that are being stored in the array.
         * @type {Integer}
         */
        this.size = size;

        /**
         * Stores the array's length divided by the size.
         * If the buffer is storing a 3-component vector (such as a position, normal, or color), then this will count the number of such vectors stored.
         * @type {Integer}
         */
        this.count = array !== undefined ? array.length / size : 0;

        /**
         * Indicates how the underlying data in the buffer maps to the values in the GLSL shader code.
         * See the constructor above for details.
         * @type {boolean}
         */
        this.normalized = normalized === true;

        /**
         * Whether the buffer is dynamic or not.
         * If false, the GPU is informed that contents of the buffer are likely to be used often and not change often.
         * This corresponds to the gl.STATIC_DRAW flag.
         * If true, the GPU is informed that contents of the buffer are likely to be used often and change often.
         * This corresponds to the gl.DYNAMIC_DRAW flag.
         * @type {boolean}
         * @default false
         */
        this.dynamic = false;

        /**
         * Object containing:
         * offset: Default is 0. Position at whcih to start update.
         * count: Default is -1, which means don't use update ranges.
         * This can be used to only update some components of stored vectors (for example, just the component related to color).
         */
        this.updateRange = { offset: 0, count: -1 };

        /**
         * A version number, incremented every time the data changes.
         * @type {Integer}
         * @default 0
         */
        this.version = 0;
    },

    setArray: function (array)
    {
        this.count = array !== undefined ? array.length / this.size : 0;

        this.array = array;

        //  inc version?

        return this;
    }

    //  copy / clone?

});

module.exports = BufferAttribute;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var TileCheckX = require('./TileCheckX');
var TileCheckY = require('./TileCheckY');
var TileIntersectsBody = require('./TileIntersectsBody');

/**
 * The core separation function to separate a physics body and a tile.
 *
 * @function Phaser.Physics.Arcade.Tilemap.SeparateTile
 * @since 3.0.0
 *
 * @param {number} i - The index of the tile within the map data.
 * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
 * @param {Phaser.Tilemaps.Tile} tile - The tile to collide against.
 * @param {Phaser.Geom.Rectangle} tileWorldRect - A rectangle-like object defining the dimensions of the tile.
 * @param {(Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} tilemapLayer - The tilemapLayer to collide against.
 * @param {number} tileBias - The tile bias value. Populated by the `World.TILE_BIAS` constant.
 * @param {boolean} isLayer - Is this check coming from a TilemapLayer or an array of tiles?
 *
 * @return {boolean} `true` if the body was separated, otherwise `false`.
 */
var SeparateTile = function (i, body, tile, tileWorldRect, tilemapLayer, tileBias, isLayer)
{
    var tileLeft = tileWorldRect.left;
    var tileTop = tileWorldRect.top;
    var tileRight = tileWorldRect.right;
    var tileBottom = tileWorldRect.bottom;
    var faceHorizontal = tile.faceLeft || tile.faceRight;
    var faceVertical = tile.faceTop || tile.faceBottom;

    if (!isLayer)
    {
        faceHorizontal = true;
        faceVertical = true;
    }

    //  We don't need to go any further if this tile doesn't actually have any colliding faces. This
    //  could happen if the tile was meant to be collided with re: a callback, but otherwise isn't
    //  needed for separation.
    if (!faceHorizontal && !faceVertical)
    {
        return false;
    }

    var ox = 0;
    var oy = 0;
    var minX = 0;
    var minY = 1;

    if (body.deltaAbsX() > body.deltaAbsY())
    {
        //  Moving faster horizontally, check X axis first
        minX = -1;
    }
    else if (body.deltaAbsX() < body.deltaAbsY())
    {
        //  Moving faster vertically, check Y axis first
        minY = -1;
    }

    if (body.deltaX() !== 0 && body.deltaY() !== 0 && faceHorizontal && faceVertical)
    {
        //  We only need do this if both axes have colliding faces AND we're moving in both
        //  directions
        minX = Math.min(Math.abs(body.position.x - tileRight), Math.abs(body.right - tileLeft));
        minY = Math.min(Math.abs(body.position.y - tileBottom), Math.abs(body.bottom - tileTop));
    }

    if (minX < minY)
    {
        if (faceHorizontal)
        {
            ox = TileCheckX(body, tile, tileLeft, tileRight, tileBias, isLayer);

            //  That's horizontal done, check if we still intersects? If not then we can return now
            if (ox !== 0 && !TileIntersectsBody(tileWorldRect, body))
            {
                return true;
            }
        }

        if (faceVertical)
        {
            oy = TileCheckY(body, tile, tileTop, tileBottom, tileBias, isLayer);
        }
    }
    else
    {
        if (faceVertical)
        {
            oy = TileCheckY(body, tile, tileTop, tileBottom, tileBias, isLayer);

            //  That's vertical done, check if we still intersects? If not then we can return now
            if (oy !== 0 && !TileIntersectsBody(tileWorldRect, body))
            {
                return true;
            }
        }

        if (faceHorizontal)
        {
            ox = TileCheckX(body, tile, tileLeft, tileRight, tileBias, isLayer);
        }
    }

    return (ox !== 0 || oy !== 0);
};

module.exports = SeparateTile;


* @param {boolean} [replaceWithNull=true] - If true, this will replace the tile at the specified location with null instead of a Tile with an index of -1.

* @return {Phaser.Tilemaps.Tile} The Tile object that was removed.

var RemoveTileAtWorldXY = function (worldX, worldY, replaceWithNull, recalculateFaces, camera, layer)

keep keep keep keep keep replace keep keep keep

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var PutTileAt = require('./PutTileAt');

/**
 * Puts a tile at the given world coordinates (pixels) in the specified layer. You can pass in either
 * an index or a Tile object. If you pass in a Tile, all attributes will be copied over to the
 * specified location. If you pass in an index, only the index at the specified location will be
 * changed. Collision information will be recalculated at the specified location.
 *
 * @function Phaser.Tilemaps.Components.PutTileAtWorldXY
 * @since 3.0.0
 *
 * @param {(integer|Phaser.Tilemaps.Tile)} tile - The index of this tile to set or a Tile object.
 * @param {number} worldX - The x coordinate, in pixels.
 * @param {number} worldY - The y coordinate, in pixels.
 * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated.
 * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values.
 * @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
 *
 * @return {Phaser.Tilemaps.Tile} The Tile object that was created or added to this map.
 */
var PutTileAtWorldXY = function (tile, worldX, worldY, recalculateFaces, camera, layer)
{
    var point = layer.tilemapLayer.worldToTileXY(worldX, worldY, true, undefined, camera, layer);
    var tileX = point.x;
    var tileY = point.y;
    return PutTileAt(tile, tileX, tileY, recalculateFaces, layer);
};

module.exports = PutTileAtWorldXY;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var PropertyValueSet = require('./PropertyValueSet');

/**
 * Takes an array of Game Objects, or any objects that have the public property `blendMode`
 * and then sets it to the given value.
 *
 * The optional `step` property is applied incrementally, multiplied by each item in the array.
 *
 * To use this with a Group: `SetBlendMode(group.getChildren(), value)`
 *
 * @function Phaser.Actions.SetBlendMode
 * @since 3.0.0
 *
 * @generic {Phaser.GameObjects.GameObject[]} G - [items,$return]
 *
 * @param {(array|Phaser.GameObjects.GameObject[])} items - The array of items to be updated by this action.
 * @param {number} value - The amount to set the property to.
 * @param {integer} [index=0] - An optional offset to start searching from within the items array.
 * @param {integer} [direction=1] - The direction to iterate through the array. 1 is from beginning to end, -1 from end to beginning.
 *
 * @return {(array|Phaser.GameObjects.GameObject[])} The array of objects that were passed to this Action.
 */
var SetBlendMode = function (items, value, index, direction)
{
    return PropertyValueSet(items, 'blendMode', value, 0, index, direction);
};

module.exports = SetBlendMode;


#ifdef USE_UV
    attribute vec2 a_Uv;
    varying vec2 v_Uv;
    uniform mat3 uvTransform;
#endif

#ifdef USE_UV2
    attribute vec2 a_Uv2;
    varying vec2 v_Uv2;
#endif

#ifdef USE_ALPHA_MAP_UV_TRANSFORM
    varying vec2 vAlphaMapUV;
    uniform mat3 alphaMapUVTransform;
#endif


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var BaseCamera = require('./BaseCamera');
var CanvasPool = require('../../display/canvas/CanvasPool');
var CenterOn = require('../../geom/rectangle/CenterOn');
var Clamp = require('../../math/Clamp');
var Class = require('../../utils/Class');
var Components = require('../../gameobjects/components');
var Effects = require('./effects');
var Linear = require('../../math/Linear');
var Rectangle = require('../../geom/rectangle/Rectangle');
var Vector2 = require('../../math/Vector2');

/**
 * @classdesc
 * A Camera.
 *
 * The Camera is the way in which all games are rendered in Phaser. They provide a view into your game world,
 * and can be positioned, rotated, zoomed and scrolled accordingly.
 *
 * A Camera consists of two elements: The viewport and the scroll values.
 *
 * The viewport is the physical position and size of the Camera within your game. Cameras, by default, are
 * created the same size as your game, but their position and size can be set to anything. This means if you
 * wanted to create a camera that was 320x200 in size, positioned in the bottom-right corner of your game,
 * you'd adjust the viewport to do that (using methods like `setViewport` and `setSize`).
 *
 * If you wish to change where the Camera is looking in your game, then you scroll it. You can do this
 * via the properties `scrollX` and `scrollY` or the method `setScroll`. Scrolling has no impact on the
 * viewport, and changing the viewport has no impact on the scrolling.
 *
 * By default a Camera will render all Game Objects it can see. You can change this using the `ignore` method,
 * allowing you to filter Game Objects out on a per-Camera basis.
 *
 * A Camera also has built-in special effects including Fade, Flash and Camera Shake.
 *
 * @class Camera
 * @memberof Phaser.Cameras.Scene2D
 * @constructor
 * @since 3.0.0
 *
 * @extends Phaser.Cameras.Scene2D.BaseCamera
 * @extends Phaser.GameObjects.Components.Flip
 * @extends Phaser.GameObjects.Components.Tint
 *
 * @param {number} x - The x position of the Camera, relative to the top-left of the game canvas.
 * @param {number} y - The y position of the Camera, relative to the top-left of the game canvas.
 * @param {number} width - The width of the Camera, in pixels.
 * @param {number} height - The height of the Camera, in pixels.
 */
var Camera = new Class({

    Extends: BaseCamera,

    Mixins: [
        Components.Flip,
        Components.Tint
    ],

    initialize:

    function Camera (x, y, width, height)
    {
        BaseCamera.call(this, x, y, width, height);

        /**
         * Does this Camera allow the Game Objects it renders to receive input events?
         *
         * @name Phaser.Cameras.Scene2D.Camera#inputEnabled
         * @type {boolean}
         * @default true
         * @since 3.0.0
         */
        this.inputEnabled = true;

        /**
         * The Camera Fade effect handler.
         * To fade this camera see the `Camera.fade` methods.
         *
         * @name Phaser.Cameras.Scene2D.Camera#fadeEffect
         * @type {Phaser.Cameras.Scene2D.Effects.Fade}
         * @since 3.5.0
         */
        this.fadeEffect = new Effects.Fade(this);

        /**
         * The Camera Flash effect handler.
         * To flash this camera see the `Camera.flash` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#flashEffect
         * @type {Phaser.Cameras.Scene2D.Effects.Flash}
         * @since 3.5.0
         */
        this.flashEffect = new Effects.Flash(this);

        /**
         * The Camera Shake effect handler.
         * To shake this camera see the `Camera.shake` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#shakeEffect
         * @type {Phaser.Cameras.Scene2D.Effects.Shake}
         * @since 3.5.0
         */
        this.shakeEffect = new Effects.Shake(this);

        /**
         * The Camera Pan effect handler.
         * To pan this camera see the `Camera.pan` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#panEffect
         * @type {Phaser.Cameras.Scene2D.Effects.Pan}
         * @since 3.11.0
         */
        this.panEffect = new Effects.Pan(this);

        /**
         * The Camera Rotate To effect handler.
         * To rotate this camera see the `Camera.rotateTo` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#rotateToEffect
         * @type {Phaser.Cameras.Scene2D.Effects.RotateTo}
         * @since 3.23.0
         */
        this.rotateToEffect = new Effects.RotateTo(this);

        /**
         * The Camera Zoom effect handler.
         * To zoom this camera see the `Camera.zoom` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#zoomEffect
         * @type {Phaser.Cameras.Scene2D.Effects.Zoom}
         * @since 3.11.0
         */
        this.zoomEffect = new Effects.Zoom(this);

        /**
         * The linear interpolation value to use when following a target.
         *
         * Can also be set via `setLerp` or as part of the `startFollow` call.
         *
         * The default values of 1 means the camera will instantly snap to the target coordinates.
         * A lower value, such as 0.1 means the camera will more slowly track the target, giving
         * a smooth transition. You can set the horizontal and vertical values independently, and also
         * adjust this value in real-time during your game.
         *
         * Be sure to keep the value between 0 and 1. A value of zero will disable tracking on that axis.
         *
         * @name Phaser.Cameras.Scene2D.Camera#lerp
         * @type {Phaser.Math.Vector2}
         * @since 3.9.0
         */
        this.lerp = new Vector2(1, 1);

        /**
         * The values stored in this property are subtracted from the Camera targets position, allowing you to
         * offset the camera from the actual target x/y coordinates by this amount.
         * Can also be set via `setFollowOffset` or as part of the `startFollow` call.
         *
         * @name Phaser.Cameras.Scene2D.Camera#followOffset
         * @type {Phaser.Math.Vector2}
         * @since 3.9.0
         */
        this.followOffset = new Vector2();

        /**
         * The Camera dead zone.
         *
         * The deadzone is only used when the camera is following a target.
         *
         * It defines a rectangular region within which if the target is present, the camera will not scroll.
         * If the target moves outside of this area, the camera will begin scrolling in order to follow it.
         *
         * The `lerp` values that you can set for a follower target also apply when using a deadzone.
         *
         * You can directly set this property to be an instance of a Rectangle. Or, you can use the
         * `setDeadzone` method for a chainable approach.
         *
         * The rectangle you provide can have its dimensions adjusted dynamically, however, please
         * note that its position is updated every frame, as it is constantly re-centered on the cameras mid point.
         *
         * Calling `setDeadzone` with no arguments will reset an active deadzone, as will setting this property
         * to `null`.
         *
         * @name Phaser.Cameras.Scene2D.Camera#deadzone
         * @type {?Phaser.Geom.Rectangle}
         * @since 3.11.0
         */
        this.deadzone = null;

        /**
         * Internal follow target reference.
         *
         * @name Phaser.Cameras.Scene2D.Camera#_follow
         * @type {?any}
         * @private
         * @default null
         * @since 3.0.0
         */
        this._follow = null;

        /**
         * Is this Camera rendering directly to the canvas or to a texture?
         *
         * Enable rendering to texture with the method `setRenderToTexture` (just enabling this boolean won't be enough)
         *
         * Once enabled you can toggle it by switching this property.
         *
         * To properly remove a render texture you should call the `clearRenderToTexture()` method.
         *
         * @name Phaser.Cameras.Scene2D.Camera#renderToTexture
         * @type {boolean}
         * @default false
         * @since 3.13.0
         */
        this.renderToTexture = false;

        /**
         * If this Camera is rendering to a texture (via `setRenderToTexture`) then you
         * have the option to control if it should also render to the Game canvas as well.
         *
         * By default, a Camera will render both to its texture and to the Game canvas.
         *
         * However, if you set ths property to `false` it will only render to the texture
         * and skip rendering to the Game canvas.
         *
         * Setting this property if the Camera isn't rendering to a texture has no effect.
         *
         * @name Phaser.Cameras.Scene2D.Camera#renderToGame
         * @type {boolean}
         * @default true
         * @since 3.23.0
         */
        this.renderToGame = true;

        /**
         * If this Camera has been set to render to a texture then this holds a reference
         * to the HTML Canvas Element that the Camera is drawing to.
         *
         * Enable texture rendering using the method `setRenderToTexture`.
         *
         * This is only populated if Phaser is running with the Canvas Renderer.
         *
         * @name Phaser.Cameras.Scene2D.Camera#canvas
         * @type {HTMLCanvasElement}
         * @since 3.13.0
         */
        this.canvas = null;

        /**
         * If this Camera has been set to render to a texture then this holds a reference
         * to the Rendering Context belonging to the Canvas element the Camera is drawing to.
         *
         * Enable texture rendering using the method `setRenderToTexture`.
         *
         * This is only populated if Phaser is running with the Canvas Renderer.
         *
         * @name Phaser.Cameras.Scene2D.Camera#context
         * @type {CanvasRenderingContext2D}
         * @since 3.13.0
         */
        this.context = null;

        /**
         * If this Camera has been set to render to a texture then this holds a reference
         * to the GL Texture belonging the Camera is drawing to.
         *
         * Enable texture rendering using the method `setRenderToTexture`.
         *
         * This is only set if Phaser is running with the WebGL Renderer.
         *
         * @name Phaser.Cameras.Scene2D.Camera#glTexture
         * @type {?WebGLTexture}
         * @since 3.13.0
         */
        this.glTexture = null;

        /**
         * If this Camera has been set to render to a texture then this holds a reference
         * to the GL Frame Buffer belonging the Camera is drawing to.
         *
         * Enable texture rendering using the method `setRenderToTexture`.
         *
         * This is only set if Phaser is running with the WebGL Renderer.
         *
         * @name Phaser.Cameras.Scene2D.Camera#framebuffer
         * @type {?WebGLFramebuffer}
         * @since 3.13.0
         */
        this.framebuffer = null;

        /**
         * If this Camera has been set to render to a texture and to use a custom pipeline,
         * then this holds a reference to the pipeline the Camera is drawing with.
         *
         * Enable texture rendering using the method `setRenderToTexture`.
         *
         * This is only set if Phaser is running with the WebGL Renderer.
         *
         * @name Phaser.Cameras.Scene2D.Camera#pipeline
         * @type {?Phaser.Renderer.WebGL.WebGLPipeline}
         * @since 3.13.0
         */
        this.pipeline = null;
    },

    /**
     * Sets the Camera to render to a texture instead of to the main canvas.
     *
     * The Camera will redirect all Game Objects it's asked to render to this texture.
     *
     * During the render sequence, the texture itself will then be rendered to the main canvas.
     *
     * Doing this gives you the ability to modify the texture before this happens,
     * allowing for special effects such as Camera specific shaders, or post-processing
     * on the texture. You can also then 'tint' the Camera.
     *
     * If running under Canvas the Camera will render to its `canvas` property.
     *
     * If running under WebGL the Camera will create a frame buffer, which is stored in its `framebuffer` and `glTexture` properties.
     *
     * If you set a camera to render to a texture then it will emit 2 events during the render loop:
     *
     * First, it will emit the event `prerender`. This happens right before any Game Object's are drawn to the Camera texture.
     *
     * Then, it will emit the event `postrender`. This happens after all Game Object's have been drawn, but right before the
     * Camera texture is rendered to the main game canvas. It's the final point at which you can manipulate the texture before
     * it appears in-game.
     *
     * You should not enable this unless you plan on actually using the texture it creates
     * somehow, otherwise you're just doubling the work required to render your game.
     *
     * If you only require the Camera to render to a texture, and not also to the Game,
     * them set the `renderToGame` parameter to `false`.
     *
     * To temporarily disable rendering to a texture, toggle the `renderToTexture` boolean.
     *
     * If you no longer require the Camera to render to a texture, call the `clearRenderToTexture` method,
     * which will delete the respective textures and free-up resources.
     *
     * @method Phaser.Cameras.Scene2D.Camera#setRenderToTexture
     * @since 3.13.0
     *
     * @param {(string|Phaser.Renderer.WebGL.WebGLPipeline)} [pipeline] - An optional WebGL Pipeline to render with, can be either a string which is the name of the pipeline, or a pipeline reference.
     * @param {boolean} [renderToGame=true] - If you do not need the Camera to still render to the Game, set this parameter to `false`.
     *
     * @return {this} This Camera instance.
     */
    setRenderToTexture: function (pipeline, renderToGame)
    {
        if (renderToGame === undefined) { renderToGame = true; }

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

        if (renderer.gl)
        {
            this.glTexture = renderer.createTextureFromSource(null, this.width, this.height, 0);
            this.framebuffer = renderer.createFramebuffer(this.width, this.height, this.glTexture, false);
        }
        else
        {
            this.canvas = CanvasPool.create2D(this, this.width, this.height);
            this.context = this.canvas.getContext('2d');
        }

        this.renderToTexture = true;
        this.renderToGame = renderToGame;

        if (pipeline)
        {
            this.setPipeline(pipeline);
        }

        return this;
    },

    /**
     * Sets the WebGL pipeline this Camera is using when rendering to a texture.
     *
     * You can pass either the string-based name of the pipeline, or a reference to the pipeline itself.
     *
     * Call this method with no arguments to clear any previously set pipeline.
     *
     * @method Phaser.Cameras.Scene2D.Camera#setPipeline
     * @since 3.13.0
     *
     * @param {(string|Phaser.Renderer.WebGL.WebGLPipeline)} [pipeline] - The WebGL Pipeline to render with, can be either a string which is the name of the pipeline, or a pipeline reference. Or if left empty it will clear the pipeline.
     *
     * @return {this} This Camera instance.
     */
    setPipeline: function (pipeline)
    {
        if (typeof pipeline === 'string')
        {
            var renderer = this.scene.sys.game.renderer;

            if (renderer.gl && renderer.pipelines.has(pipeline))
            {
                this.pipeline = renderer.pipelines.get(pipeline);
            }
        }
        else
        {
            this.pipeline = pipeline;
        }

        return this;
    },

    /**
     * If this Camera was set to render to a texture, this will clear the resources it was using and
     * redirect it to render back to the primary Canvas again.
     *
     * If you only wish to temporarily disable rendering to a texture then you can toggle the
     * property `renderToTexture` instead.
     *
     * @method Phaser.Cameras.Scene2D.Camera#clearRenderToTexture
     * @since 3.13.0
     *
     * @return {this} This Camera instance.
     */
    clearRenderToTexture: function ()
    {
        if (!this.scene)
        {
            return;
        }

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

        if (!renderer)
        {
            return;
        }

        if (renderer.gl)
        {
            if (this.framebuffer)
            {
                renderer.deleteFramebuffer(this.framebuffer);
            }

            if (this.glTexture)
            {
                renderer.deleteTexture(this.glTexture);
            }

            this.framebuffer = null;
            this.glTexture = null;
            this.pipeline = null;
        }
        else
        {
            CanvasPool.remove(this);

            this.canvas = null;
            this.context = null;
        }

        this.renderToTexture = false;

        return this;
    },

    /**
     * Sets the Camera dead zone.
     *
     * The deadzone is only used when the camera is following a target.
     *
     * It defines a rectangular region within which if the target is present, the camera will not scroll.
     * If the target moves outside of this area, the camera will begin scrolling in order to follow it.
     *
     * The deadzone rectangle is re-positioned every frame so that it is centered on the mid-point
     * of the camera. This allows you to use the object for additional game related checks, such as
     * testing if an object is within it or not via a Rectangle.contains call.
     *
     * The `lerp` values that you can set for a follower target also apply when using a deadzone.
     *
     * Calling this method with no arguments will reset an active deadzone.
     *
     * @method Phaser.Cameras.Scene2D.Camera#setDeadzone
     * @since 3.11.0
     *
     * @param {number} [width] - The width of the deadzone rectangle in pixels. If not specified the deadzone is removed.
     * @param {number} [height] - The height of the deadzone rectangle in pixels.
     *
     * @return {this} This Camera instance.
     */
    setDeadzone: function (width, height)
    {
        if (width === undefined)
        {
            this.deadzone = null;
        }
        else
        {
            if (this.deadzone)
            {
                this.deadzone.width = width;
                this.deadzone.height = height;
            }
            else
            {
                this.deadzone = new Rectangle(0, 0, width, height);
            }

            if (this._follow)
            {
                var originX = this.width / 2;
                var originY = this.height / 2;

                var fx = this._follow.x - this.followOffset.x;
                var fy = this._follow.y - this.followOffset.y;

                this.midPoint.set(fx, fy);

                this.scrollX = fx - originX;
                this.scrollY = fy - originY;
            }

            CenterOn(this.deadzone, this.midPoint.x, this.midPoint.y);
        }

        return this;
    },

    /**
     * Fades the Camera in from the given color over the duration specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#fadeIn
     * @fires Phaser.Cameras.Scene2D.Events#FADE_IN_START
     * @fires Phaser.Cameras.Scene2D.Events#FADE_IN_COMPLETE
     * @since 3.3.0
     *
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {integer} [red=0] - The amount to fade the red channel towards. A value between 0 and 255.
     * @param {integer} [green=0] - The amount to fade the green channel towards. A value between 0 and 255.
     * @param {integer} [blue=0] - The amount to fade the blue channel towards. A value between 0 and 255.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    fadeIn: function (duration, red, green, blue, callback, context)
    {
        return this.fadeEffect.start(false, duration, red, green, blue, true, callback, context);
    },

    /**
     * Fades the Camera out to the given color over the duration specified.
     * This is an alias for Camera.fade that forces the fade to start, regardless of existing fades.
     *
     * @method Phaser.Cameras.Scene2D.Camera#fadeOut
     * @fires Phaser.Cameras.Scene2D.Events#FADE_OUT_START
     * @fires Phaser.Cameras.Scene2D.Events#FADE_OUT_COMPLETE
     * @since 3.3.0
     *
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {integer} [red=0] - The amount to fade the red channel towards. A value between 0 and 255.
     * @param {integer} [green=0] - The amount to fade the green channel towards. A value between 0 and 255.
     * @param {integer} [blue=0] - The amount to fade the blue channel towards. A value between 0 and 255.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    fadeOut: function (duration, red, green, blue, callback, context)
    {
        return this.fadeEffect.start(true, duration, red, green, blue, true, callback, context);
    },

    /**
     * Fades the Camera from the given color to transparent over the duration specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#fadeFrom
     * @fires Phaser.Cameras.Scene2D.Events#FADE_IN_START
     * @fires Phaser.Cameras.Scene2D.Events#FADE_IN_COMPLETE
     * @since 3.5.0
     *
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {integer} [red=0] - The amount to fade the red channel towards. A value between 0 and 255.
     * @param {integer} [green=0] - The amount to fade the green channel towards. A value between 0 and 255.
     * @param {integer} [blue=0] - The amount to fade the blue channel towards. A value between 0 and 255.
     * @param {boolean} [force=false] - Force the effect to start immediately, even if already running.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    fadeFrom: function (duration, red, green, blue, force, callback, context)
    {
        return this.fadeEffect.start(false, duration, red, green, blue, force, callback, context);
    },

    /**
     * Fades the Camera from transparent to the given color over the duration specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#fade
     * @fires Phaser.Cameras.Scene2D.Events#FADE_OUT_START
     * @fires Phaser.Cameras.Scene2D.Events#FADE_OUT_COMPLETE
     * @since 3.0.0
     *
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {integer} [red=0] - The amount to fade the red channel towards. A value between 0 and 255.
     * @param {integer} [green=0] - The amount to fade the green channel towards. A value between 0 and 255.
     * @param {integer} [blue=0] - The amount to fade the blue channel towards. A value between 0 and 255.
     * @param {boolean} [force=false] - Force the effect to start immediately, even if already running.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    fade: function (duration, red, green, blue, force, callback, context)
    {
        return this.fadeEffect.start(true, duration, red, green, blue, force, callback, context);
    },

    /**
     * Flashes the Camera by setting it to the given color immediately and then fading it away again quickly over the duration specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#flash
     * @fires Phaser.Cameras.Scene2D.Events#FLASH_START
     * @fires Phaser.Cameras.Scene2D.Events#FLASH_COMPLETE
     * @since 3.0.0
     *
     * @param {integer} [duration=250] - The duration of the effect in milliseconds.
     * @param {integer} [red=255] - The amount to fade the red channel towards. A value between 0 and 255.
     * @param {integer} [green=255] - The amount to fade the green channel towards. A value between 0 and 255.
     * @param {integer} [blue=255] - The amount to fade the blue channel towards. A value between 0 and 255.
     * @param {boolean} [force=false] - Force the effect to start immediately, even if already running.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    flash: function (duration, red, green, blue, force, callback, context)
    {
        return this.flashEffect.start(duration, red, green, blue, force, callback, context);
    },

    /**
     * Shakes the Camera by the given intensity over the duration specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#shake
     * @fires Phaser.Cameras.Scene2D.Events#SHAKE_START
     * @fires Phaser.Cameras.Scene2D.Events#SHAKE_COMPLETE
     * @since 3.0.0
     *
     * @param {integer} [duration=100] - The duration of the effect in milliseconds.
     * @param {(number|Phaser.Math.Vector2)} [intensity=0.05] - The intensity of the shake.
     * @param {boolean} [force=false] - Force the shake effect to start immediately, even if already running.
     * @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    shake: function (duration, intensity, force, callback, context)
    {
        return this.shakeEffect.start(duration, intensity, force, callback, context);
    },

    /**
     * This effect will scroll the Camera so that the center of its viewport finishes at the given destination,
     * over the duration and with the ease specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#pan
     * @fires Phaser.Cameras.Scene2D.Events#PAN_START
     * @fires Phaser.Cameras.Scene2D.Events#PAN_COMPLETE
     * @since 3.11.0
     *
     * @param {number} x - The destination x coordinate to scroll the center of the Camera viewport to.
     * @param {number} y - The destination y coordinate to scroll the center of the Camera viewport to.
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {(string|function)} [ease='Linear'] - The ease to use for the pan. Can be any of the Phaser Easing constants or a custom function.
     * @param {boolean} [force=false] - Force the pan effect to start immediately, even if already running.
     * @param {Phaser.Types.Cameras.Scene2D.CameraPanCallback} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent four arguments: A reference to the camera, a progress amount between 0 and 1 indicating how complete the effect is,
     * the current camera scroll x coordinate and the current camera scroll y coordinate.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    pan: function (x, y, duration, ease, force, callback, context)
    {
        return this.panEffect.start(x, y, duration, ease, force, callback, context);
    },

    /**
     * This effect will rotate the Camera so that the viewport finishes at the given angle in radians,
     * over the duration and with the ease specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#rotateTo
     * @since 3.23.0
     *
     * @param {number} radians - The destination angle in radians to rotate the Camera viewport to. If the angle is positive then the rotation is clockwise else anticlockwise
     * @param {boolean} [shortestPath=false] - If shortest path is set to true the camera will rotate in the quickest direction clockwise or anti-clockwise.
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {(string|function)} [ease='Linear'] - The ease to use for the rotation. Can be any of the Phaser Easing constants or a custom function.
     * @param {boolean} [force=false] - Force the rotation effect to start immediately, even if already running.
     * @param {CameraRotateCallback} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent four arguments: A reference to the camera, a progress amount between 0 and 1 indicating how complete the effect is,
     * the current camera rotation angle in radians.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {Phaser.Cameras.Scene2D.Camera} This Camera instance.
     */
    rotateTo: function (radians, shortestPath, duration, ease, force, callback, context)
    {
        return this.rotateToEffect.start(radians, shortestPath, duration, ease, force, callback, context);
    },

    /**
     * This effect will zoom the Camera to the given scale, over the duration and with the ease specified.
     *
     * @method Phaser.Cameras.Scene2D.Camera#zoomTo
     * @fires Phaser.Cameras.Scene2D.Events#ZOOM_START
     * @fires Phaser.Cameras.Scene2D.Events#ZOOM_COMPLETE
     * @since 3.11.0
     *
     * @param {number} zoom - The target Camera zoom value.
     * @param {integer} [duration=1000] - The duration of the effect in milliseconds.
     * @param {(string|function)} [ease='Linear'] - The ease to use for the pan. Can be any of the Phaser Easing constants or a custom function.
     * @param {boolean} [force=false] - Force the pan effect to start immediately, even if already running.
     * @param {Phaser.Types.Cameras.Scene2D.CameraPanCallback} [callback] - This callback will be invoked every frame for the duration of the effect.
     * It is sent four arguments: A reference to the camera, a progress amount between 0 and 1 indicating how complete the effect is,
     * the current camera scroll x coordinate and the current camera scroll y coordinate.
     * @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
     *
     * @return {this} This Camera instance.
     */
    zoomTo: function (zoom, duration, ease, force, callback, context)
    {
        return this.zoomEffect.start(zoom, duration, ease, force, callback, context);
    },

    /**
     * Internal preRender step.
     *
     * @method Phaser.Cameras.Scene2D.Camera#preRender
     * @protected
     * @since 3.0.0
     */
    preRender: function ()
    {
        var width = this.width;
        var height = this.height;

        var halfWidth = width * 0.5;
        var halfHeight = height * 0.5;

        var zoom = this.zoom;
        var matrix = this.matrix;

        var originX = width * this.originX;
        var originY = height * this.originY;

        var follow = this._follow;
        var deadzone = this.deadzone;

        var sx = this.scrollX;
        var sy = this.scrollY;

        if (deadzone)
        {
            CenterOn(deadzone, this.midPoint.x, this.midPoint.y);
        }

        if (follow && !this.panEffect.isRunning)
        {
            var fx = (follow.x - this.followOffset.x);
            var fy = (follow.y - this.followOffset.y);

            if (deadzone)
            {
                if (fx < deadzone.x)
                {
                    sx = Linear(sx, sx - (deadzone.x - fx), this.lerp.x);
                }
                else if (fx > deadzone.right)
                {
                    sx = Linear(sx, sx + (fx - deadzone.right), this.lerp.x);
                }

                if (fy < deadzone.y)
                {
                    sy = Linear(sy, sy - (deadzone.y - fy), this.lerp.y);
                }
                else if (fy > deadzone.bottom)
                {
                    sy = Linear(sy, sy + (fy - deadzone.bottom), this.lerp.y);
                }
            }
            else
            {
                sx = Linear(sx, fx - originX, this.lerp.x);
                sy = Linear(sy, fy - originY, this.lerp.y);
            }
        }

        if (this.useBounds)
        {
            sx = this.clampX(sx);
            sy = this.clampY(sy);
        }

        if (this.roundPixels)
        {
            originX = Math.round(originX);
            originY = Math.round(originY);
        }

        //  Values are in pixels and not impacted by zooming the Camera
        this.scrollX = sx;
        this.scrollY = sy;

        var midX = sx + halfWidth;
        var midY = sy + halfHeight;

        //  The center of the camera, in world space, so taking zoom into account
        //  Basically the pixel value of what it's looking at in the middle of the cam
        this.midPoint.set(midX, midY);

        var displayWidth = width / zoom;
        var displayHeight = height / zoom;

        this.worldView.setTo(
            midX - (displayWidth / 2),
            midY - (displayHeight / 2),
            displayWidth,
            displayHeight
        );

        matrix.applyITRS(this.x + originX, this.y + originY, this.rotation, zoom, zoom);
        matrix.translate(-originX, -originY);

        this.shakeEffect.preRender();
    },

    /**
     * Sets the linear interpolation value to use when following a target.
     *
     * The default values of 1 means the camera will instantly snap to the target coordinates.
     * A lower value, such as 0.1 means the camera will more slowly track the target, giving
     * a smooth transition. You can set the horizontal and vertical values independently, and also
     * adjust this value in real-time during your game.
     *
     * Be sure to keep the value between 0 and 1. A value of zero will disable tracking on that axis.
     *
     * @method Phaser.Cameras.Scene2D.Camera#setLerp
     * @since 3.9.0
     *
     * @param {number} [x=1] - The amount added to the horizontal linear interpolation of the follow target.
     * @param {number} [y=1] - The amount added to the vertical linear interpolation of the follow target.
     *
     * @return {this} This Camera instance.
     */
    setLerp: function (x, y)
    {
        if (x === undefined) { x = 1; }
        if (y === undefined) { y = x; }

        this.lerp.set(x, y);

        return this;
    },

    /**
     * Sets the horizontal and vertical offset of the camera from its follow target.
     * The values are subtracted from the targets position during the Cameras update step.
     *
     * @method Phaser.Cameras.Scene2D.Camera#setFollowOffset
     * @since 3.9.0
     *
     * @param {number} [x=0] - The horizontal offset from the camera follow target.x position.
     * @param {number} [y=0] - The vertical offset from the camera follow target.y position.
     *
     * @return {this} This Camera instance.
     */
    setFollowOffset: function (x, y)
    {
        if (x === undefined) { x = 0; }
        if (y === undefined) { y = 0; }

        this.followOffset.set(x, y);

        return this;
    },

    /**
     * Sets the Camera to follow a Game Object.
     *
     * When enabled the Camera will automatically adjust its scroll position to keep the target Game Object
     * in its center.
     *
     * You can set the linear interpolation value used in the follow code.
     * Use low lerp values (such as 0.1) to automatically smooth the camera motion.
     *
     * If you find you're getting a slight "jitter" effect when following an object it's probably to do with sub-pixel
     * rendering of the targets position. This can be rounded by setting the `roundPixels` argument to `true` to
     * force full pixel rounding rendering. Note that this can still be broken if you have specified a non-integer zoom
     * value on the camera. So be sure to keep the camera zoom to integers.
     *
     * @method Phaser.Cameras.Scene2D.Camera#startFollow
     * @since 3.0.0
     *
     * @param {(Phaser.GameObjects.GameObject|object)} target - The target for the Camera to follow.
     * @param {boolean} [roundPixels=false] - Round the camera position to whole integers to avoid sub-pixel rendering?
     * @param {number} [lerpX=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when horizontally tracking the target. The closer the value to 1, the faster the camera will track.
     * @param {number} [lerpY=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when vertically tracking the target. The closer the value to 1, the faster the camera will track.
     * @param {number} [offsetX=0] - The horizontal offset from the camera follow target.x position.
     * @param {number} [offsetY=0] - The vertical offset from the camera follow target.y position.
     *
     * @return {this} This Camera instance.
     */
    startFollow: function (target, roundPixels, lerpX, lerpY, offsetX, offsetY)
    {
        if (roundPixels === undefined) { roundPixels = false; }
        if (lerpX === undefined) { lerpX = 1; }
        if (lerpY === undefined) { lerpY = lerpX; }
        if (offsetX === undefined) { offsetX = 0; }
        if (offsetY === undefined) { offsetY = offsetX; }

        this._follow = target;

        this.roundPixels = roundPixels;

        lerpX = Clamp(lerpX, 0, 1);
        lerpY = Clamp(lerpY, 0, 1);

        this.lerp.set(lerpX, lerpY);

        this.followOffset.set(offsetX, offsetY);

        var originX = this.width / 2;
        var originY = this.height / 2;

        var fx = target.x - offsetX;
        var fy = target.y - offsetY;

        this.midPoint.set(fx, fy);

        this.scrollX = fx - originX;
        this.scrollY = fy - originY;

        if (this.useBounds)
        {
            this.scrollX = this.clampX(this.scrollX);
            this.scrollY = this.clampY(this.scrollY);
        }

        return this;
    },

    /**
     * Stops a Camera from following a Game Object, if previously set via `Camera.startFollow`.
     *
     * @method Phaser.Cameras.Scene2D.Camera#stopFollow
     * @since 3.0.0
     *
     * @return {this} This Camera instance.
     */
    stopFollow: function ()
    {
        this._follow = null;

        return this;
    },

    /**
     * Resets any active FX, such as a fade, flash or shake. Useful to call after a fade in order to
     * remove the fade.
     *
     * @method Phaser.Cameras.Scene2D.Camera#resetFX
     * @since 3.0.0
     *
     * @return {this} This Camera instance.
     */
    resetFX: function ()
    {
        this.rotateToEffect.reset();
        this.panEffect.reset();
        this.shakeEffect.reset();
        this.flashEffect.reset();
        this.fadeEffect.reset();

        return this;
    },

    /**
     * Internal method called automatically by the Camera Manager.
     *
     * @method Phaser.Cameras.Scene2D.Camera#update
     * @protected
     * @since 3.0.0
     *
     * @param {integer} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time, in ms, elapsed since the last frame.
     */
    update: function (time, delta)
    {
        if (this.visible)
        {
            this.rotateToEffect.update(time, delta);
            this.panEffect.update(time, delta);
            this.zoomEffect.update(time, delta);
            this.shakeEffect.update(time, delta);
            this.flashEffect.update(time, delta);
            this.fadeEffect.update(time, delta);
        }
    },

    /**
     * Destroys this Camera instance. You rarely need to call this directly.
     *
     * Called by the Camera Manager. If you wish to destroy a Camera please use `CameraManager.remove` as
     * cameras are stored in a pool, ready for recycling later, and calling this directly will prevent that.
     *
     * @method Phaser.Cameras.Scene2D.Camera#destroy
     * @fires Phaser.Cameras.Scene2D.Events#DESTROY
     * @since 3.0.0
     */
    destroy: function ()
    {
        this.clearRenderToTexture();

        this.resetFX();

        BaseCamera.prototype.destroy.call(this);

        this._follow = null;

        this.deadzone = null;
    }

});

module.exports = Camera;


keep keep keep replace replace replace replace keep keep keep

return RemoveTileAt(point.x, point.y, replaceWithNull, recalculateFaces, layer);

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var RemoveTileAt = require('./RemoveTileAt');

/**
 * Removes the tile at the given world coordinates in the specified layer and updates the layer's
 * collision information.
 *
 * @function Phaser.Tilemaps.Components.RemoveTileAtWorldXY
 * @since 3.0.0
 *
 * @param {number} worldX - The x coordinate, in pixels.
 * @param {number} worldY - The y coordinate, in pixels.
 * @param {boolean} [replaceWithNull=true] - If true, this will replace the tile at the specified location with null instead of a Tile with an index of -1.
 * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated.
 * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values.
 * @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
 *
 * @return {Phaser.Tilemaps.Tile} The Tile object that was removed.
 */
var RemoveTileAtWorldXY = function (worldX, worldY, replaceWithNull, recalculateFaces, camera, layer)
{
    var point = layer.tilemapLayer.worldToTileXY(worldX, worldY, true, undefined, camera, layer);
    var tileX = point.x;
    var tileY = point.y;
    return RemoveTileAt(tileX, tileY, replaceWithNull, recalculateFaces, layer);
};

module.exports = RemoveTileAtWorldXY;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Compute a random position vector in a spherical area, optionally defined by the given radius.
 *
 * @function Phaser.Math.RandomXYZ
 * @since 3.0.0
 *
 * @param {Phaser.Math.Vector3} vec3 - The Vector to compute random values for.
 * @param {number} [radius=1] - The radius.
 *
 * @return {Phaser.Math.Vector3} The given Vector.
 */
var RandomXYZ = function (vec3, radius)
{
    if (radius === undefined) { radius = 1; }

    var r = Math.random() * 2 * Math.PI;
    var z = (Math.random() * 2) - 1;
    var zScale = Math.sqrt(1 - z * z) * radius;

    vec3.x = Math.cos(r) * zScale;
    vec3.y = Math.sin(r) * zScale;
    vec3.z = z * radius;

    return vec3;
};

module.exports = RandomXYZ;


/**
 * performance.now
 */
(function () {

    if ('performance' in window === false)
    {
        window.performance = {};
    }

    //  Thanks IE8
    Date.now = (Date.now || function () {
        return new Date().getTime();
    });

    if ('now' in window.performance === false)
    {
        var nowOffset = Date.now();

        if (performance.timing && performance.timing.navigationStart)
        {
            nowOffset = performance.timing.navigationStart;
        }

        window.performance.now = function now ()
        {
            return Date.now() - nowOffset;
        }
    }

})();


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Check if a given value is an even number.
 *
 * @function Phaser.Math.IsEven
 * @since 3.0.0
 *
 * @param {number} value - The number to perform the check with.
 *
 * @return {boolean} Whether the number is even or not.
 */
var IsEven = function (value)
{
    // Use abstract equality == for "is number" test

    // eslint-disable-next-line eqeqeq
    return (value == parseFloat(value)) ? !(value % 2) : void 0;
};

module.exports = IsEven;


keep keep keep keep add keep keep keep keep keep

* Fixed a bug where map would occasionally break while multi-touch-zooming on iOS. [#32]

Leaflet Changelog
=================

## 0.2 (master)

 * Added **WMS support** (L.TileLayer.WMS), currently EPSG:3857 only.
 * `L.Circle` is now zoom-dependent (with radius in meters); circle of a permanent size is now called `L.CircleMarker`.
 * Disabled zoom animation on Android by default because it's buggy on some devices (will be enabled back when it's stable enough). [#32](https://github.com/CloudMade/Leaflet/issues/32)
 * Added `mouseover` and `mouseout` events to map, markers and paths; added map `mousemove` event.
 * Added `setLatLng` method to `L.Marker`.
 * Added `maxZoom` argument to `map.locateAndSetView` method.
 * Improved geolocation error handling: better error messages, explicit timeout, set world view on locateAndSetView failure. [#61](https://github.com/CloudMade/Leaflet/issues/61)
 * Fixed a bug where paths would not appear in IE8.
 * Fixed a bug where zooming is broken if the map contains a polygon and you zoom to an area where it's not visible. [#47](https://github.com/CloudMade/Leaflet/issues/47)
 * Fixed a bug where closed polylines would not appear on the map.
 * Fixed incorrect zoom animation & popup styling in Opera 11.11.
 * Fixed a bug where double click zoom wouldn't work if popup is opened on map click
 * Fixed a bug where map isn't displayed in Firefox when there's an `img { max-width: 100% }` rule.
 * Fixed inability to remove ImageOverlay layer.

## 0.1 (2011-05-13)

 * Initial Leaflet release.


L.Control.Attribution = L.Class.extend({
	onAdd: function(map) {
		this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
		this._map = map;
		this._prefix = 'Powered by Leaflet';
		this._attributions = {};
		this._update();
	},

	getPosition: function() {
		return L.Control.Position.BOTTOM_RIGHT;
	},

	getContainer: function() {
		return this._container;
	},

	setPrefix: function(prefix) {
		this._prefix = prefix;
	},

	addAttribution: function(text) {
		if (!text) return;
		this._attributions[text] = true;
		this._update();
	},

	removeAttribution: function(text) {
		if (!text) return;
		delete this._attributions[text];
		this._update();
	},

	_update: function() {
		if (!this._map) return;

		var attribs = [];

		for (var i in this._attributions) {
			if (this._attributions.hasOwnProperty(i)) {
				attribs.push(i);
			}
		}

		this._container.innerHTML = [this._prefix, attribs.join(', ')].join(' — ');
	}
});


describe('LatLng', function() {
	describe('constructor', function() {
		it("should set lat and lng", function() {
			var a = new L.LatLng(25, 74);
			expect(a.lat).toEqual(25);
			expect(a.lng).toEqual(74);

			var a = new L.LatLng(-25, -74);
			expect(a.lat).toEqual(-25);
			expect(a.lng).toEqual(-74);
		});

		it("should clamp latitude to lie between -90 and 90", function() {
			var a = new L.LatLng(150, 0).lat;
			expect(a).toEqual(90);

			var b = new L.LatLng(-230, 0).lat;
			expect(b).toEqual(-90);
		});

		it("should clamp longtitude to lie between -180 and 180", function() {
			var a = new L.LatLng(0, 190).lng;
			expect(a).toEqual(-170);

			var b = new L.LatLng(0, 360).lng;
			expect(b).toEqual(0);

			var c = new L.LatLng(0, 380).lng;
			expect(c).toEqual(20);

			var d = new L.LatLng(0, -190).lng;
			expect(d).toEqual(170);

			var e = new L.LatLng(0, -360).lng;
			expect(e).toEqual(0);

			var f = new L.LatLng(0, -380).lng;
			expect(f).toEqual(-20);
		});

		it("should not clamp latitude and longtitude if unbounded flag set to true", function() {
			var a = new L.LatLng(150, 0, true).lat;
			expect(a).toEqual(150);

			var b = new L.LatLng(-230, 0, true).lat;
			expect(b).toEqual(-230);

			var c = new L.LatLng(0, 250, true).lng;
			expect(c).toEqual(250);

			var d = new L.LatLng(0, -190, true).lng;
			expect(d).toEqual(-190);
		});
	});

	describe('#equals', function() {
		it("should return true if compared objects are equal within a certain margin", function() {
			var a = new L.LatLng(10, 20);
			var b = new L.LatLng(10 + 1.0E-10, 20 - 1.0E-10);
			expect(a.equals(b)).toBe(true);
		});

		it("should return false if compared objects are not equal within a certain margin", function() {
			var a = new L.LatLng(10, 20);
			var b = new L.LatLng(10, 23.3);
			expect(a.equals(b)).toBe(false);
		});
	});
});


L.TileLayer.WMS = L.TileLayer.extend({
	defaultWmsParams: {
		service: 'WMS',
		request: 'GetMap',
		version: '1.1.1',
		layers: '',
		styles: '',
		format: 'image/jpeg',
		transparent: false
	},

	initialize: function(/*String*/ url, /*Object*/ options) {
		this._url = url;

		this.wmsParams = L.Util.extend({}, this.defaultWmsParams);
		this.wmsParams.width = this.wmsParams.height = this.options.tileSize;

		for (var i in options) {
			// all keys that are not TileLayer options go to WMS params
			if (!this.options.hasOwnProperty(i)) {
				this.wmsParams[i] = options[i];
			}
		}
		var projectionKey = (parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs');
		this.wmsParams[projectionKey] = 'EPSG:3857';

		L.Util.setOptions(this, options);
	},

	getTileUrl: function(/*Point*/ tilePoint, /*Number*/ zoom)/*-> String*/ {
		var tileSize = this.options.tileSize,
			nwPoint = tilePoint.multiplyBy(tileSize),
			sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),
			nwMerc = this._map.unproject(nwPoint),
			seMerc = this._map.unproject(sePoint),
			r = 6378137,
			nw = L.Projection.Mercator.project(nwMerc).multiplyBy(r),
			se = L.Projection.Mercator.project(seMerc).multiplyBy(r),
			bbox = [nw.x, se.y, se.x, nw.y].join(',');

		return this._url + L.Util.getParamString(this.wmsParams) + "&bbox=" + bbox;
	}
});