phaser/src/textures/CanvasTexture.js

356 lines
11 KiB
JavaScript
Raw Normal View History

2018-04-23 17:37:44 +00:00
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var Class = require('../utils/Class');
var Color = require('../display/color/Color');
var IsSizePowerOfTwo = require('../math/pow2/IsSizePowerOfTwo');
2018-04-23 17:37:44 +00:00
var Texture = require('./Texture');
/**
* @classdesc
* A Canvas Texture is a special kind of Texture that is backed by an HTML Canvas Element as its source.
*
* You can use the properties of this texture to draw to the canvas element directly, using all of the standard
* canvas operations available in the browser. Any Game Object can be given this texture and will render with it.
*
* Note: When running under WebGL the Canvas Texture needs to re-generate its base WebGLTexture and reupload it to
* the GPU every time you modify it, otherwise the changes you make to this texture will not be visible. To do this
* you should call `CanvasTexture.refresh()` once you are finished with your changes to the canvas. Try and keep
* this to a minimum, especially on large canvas sizes, or you may inadvertently thrash the GPU by constantly uploading
* texture data to it. This restriction does not apply if using the Canvas Renderer.
*
* It starts with only one frame that covers the whole of the canvas. You can add further frames, that specify
* sections of the canvas using the `add` method.
*
* Should you need to resize the canvas use the `setSize` method so that it accurately updates all of the underlying
* texture data as well. Forgetting to do this (i.e. by changing the canvas size directly from your code) could cause
* graphical errors.
2018-04-23 17:37:44 +00:00
*
* @class CanvasTexture
* @extends Phaser.Textures.Texture
* @memberOf Phaser.Textures
* @constructor
2018-05-04 17:51:02 +00:00
* @since 3.7.0
2018-04-23 17:37:44 +00:00
*
* @param {Phaser.Textures.CanvasTexture} manager - A reference to the Texture Manager this Texture belongs to.
2018-04-23 17:37:44 +00:00
* @param {string} key - The unique string-based key of this Texture.
* @param {HTMLCanvasElement} source - The canvas element that is used as the base of this texture.
* @param {integer} width - The width of the canvas.
* @param {integer} height - The height of the canvas.
2018-04-23 17:37:44 +00:00
*/
var CanvasTexture = new Class({
Extends: Texture,
initialize:
function CanvasTexture (manager, key, source, width, height)
{
Texture.call(this, manager, key, source, width, height);
this.add('__BASE', 0, 0, 0, width, height);
/**
* A reference to the Texture Source of this Canvas.
*
2018-09-27 13:16:09 +00:00
* @name Phaser.Textures.CanvasTexture#_source
* @type {Phaser.Textures.TextureSource}
* @private
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*/
this._source = this.frames['__BASE'].source;
/**
* The source Canvas Element.
*
* @name Phaser.Textures.CanvasTexture#canvas
* @readOnly
* @type {HTMLCanvasElement}
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*/
this.canvas = this._source.image;
/**
* The 2D Canvas Rendering Context.
*
2018-09-27 13:16:09 +00:00
* @name Phaser.Textures.CanvasTexture#context
* @readOnly
* @type {CanvasRenderingContext2D}
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*/
2018-04-23 17:37:44 +00:00
this.context = this.canvas.getContext('2d');
/**
* The width of the Canvas.
2018-09-10 19:44:19 +00:00
* This property is read-only, if you wish to change it use the `setSize` method.
*
* @name Phaser.Textures.CanvasTexture#width
* @readOnly
* @type {integer}
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*/
2018-04-23 17:37:44 +00:00
this.width = width;
/**
* The height of the Canvas.
2018-09-10 19:44:19 +00:00
* This property is read-only, if you wish to change it use the `setSize` method.
*
* @name Phaser.Textures.CanvasTexture#height
* @readOnly
* @type {integer}
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*/
2018-04-23 17:37:44 +00:00
this.height = height;
/**
* The context image data.
* Use the `update` method to populate this when the canvas changes.
*
* @name Phaser.Textures.CanvasTexture#imageData
* @type {ImageData}
* @since 3.13.0
*/
this.imageData = this.context.getImageData(0, 0, width, height);
/**
* A Uint8ClampedArray view into the `buffer`.
* Use the `update` method to populate this when the canvas changes.
* Note that this is unavailable in some browsers, such as Epic Browser, due to their security restrictions.
*
2018-09-10 19:44:19 +00:00
* @name Phaser.Textures.CanvasTexture#data
* @type {Uint8ClampedArray}
* @since 3.13.0
*/
this.data = null;
if (this.imageData)
{
this.data = this.imageData.data;
}
/**
* An Uint32Array view into the `buffer`.
*
* @name Phaser.Textures.CanvasTexture#pixels
* @type {Uint32Array}
* @since 3.13.0
*/
this.pixels = null;
/**
* An ArrayBuffer the same size as the context ImageData.
*
* @name Phaser.Textures.CanvasTexture#buffer
* @type {ArrayBuffer}
* @since 3.13.0
*/
this.buffer;
if (this.data)
{
if (this.imageData.data.buffer)
{
this.buffer = this.imageData.data.buffer;
this.pixels = new Uint32Array(this.buffer);
}
2018-09-10 19:44:19 +00:00
else if (window.ArrayBuffer)
{
this.buffer = new ArrayBuffer(this.imageData.data.length);
this.pixels = new Uint32Array(this.buffer);
}
else
{
this.pixels = this.imageData.data;
}
}
},
/**
* This re-creates the `imageData` from the current context.
* It then re-builds the ArrayBuffer, the `data` Uint8ClampedArray reference and the `pixels` Int32Array.
*
* Warning: This is a very expensive operation, so use it sparingly.
*
* @method Phaser.Textures.CanvasTexture#update
* @since 3.13.0
*
* @return {Phaser.Textures.CanvasTexture} This CanvasTexture.
2018-09-10 19:44:19 +00:00
*/
update: function ()
{
2018-09-08 00:19:25 +00:00
this.imageData = this.context.getImageData(0, 0, this.width, this.height);
this.data = this.imageData.data;
if (this.imageData.data.buffer)
{
this.buffer = this.imageData.data.buffer;
this.pixels = new Uint32Array(this.buffer);
}
else if (window.ArrayBuffer)
{
this.buffer = new ArrayBuffer(this.imageData.data.length);
this.pixels = new Uint32Array(this.buffer);
}
else
{
this.pixels = this.imageData.data;
}
return this;
},
2018-09-10 19:44:19 +00:00
/**
* Draws the given Image or Canvas element to this CanvasTexture, then updates the internal
* ImageData buffer and arrays.
*
* @method Phaser.Textures.CanvasTexture#draw
* @since 3.13.0
*
* @param {integer} x - The x coordinate to draw the source at.
* @param {integer} y - The y coordinate to draw the source at.
* @param {(HTMLImageElement|HTMLCanvasElement)} source - The element to draw to this canvas.
*
* @return {Phaser.Textures.CanvasTexture} This CanvasTexture.
*/
2018-09-08 00:19:25 +00:00
draw: function (x, y, source)
{
this.context.drawImage(source, x, y);
return this.update();
},
/**
2018-09-10 19:44:19 +00:00
* Get the color of a specific pixel from this texture and store it in a Color object.
*
2018-09-10 19:44:19 +00:00
* If you have drawn anything to this CanvasTexture since it was created you must call `CanvasTexture.update` to refresh the array buffer,
* otherwise this may return out of date color values, or worse - throw a run-time error as it tries to access an array element that doesn't exist.
*
* @method Phaser.Textures.CanvasTexture#getPixel
* @since 3.13.0
*
2018-09-08 00:19:25 +00:00
* @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this CanvasTexture and be an integer.
* @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this CanvasTexture and be an integer.
* @param {Phaser.Display.Color} [out] - An object into which 4 properties will be set: r, g, b and a. If not provided a Color object will be created.
*
2018-09-08 00:19:25 +00:00
* @return {Phaser.Display.Color} An object with the red, green, blue and alpha values set in the r, g, b and a properties.
*/
getPixel: function (x, y, out)
{
if (!out)
{
out = new Color();
}
var index = ~~(x + (y * this.width));
index *= 4;
2018-09-10 19:44:19 +00:00
var r = this.data[index];
var g = this.data[++index];
var b = this.data[++index];
var a = this.data[++index];
2018-09-10 19:44:19 +00:00
return out.setTo(r, g, b, a);
2018-04-23 17:37:44 +00:00
},
/**
* This should be called manually if you are running under WebGL.
* It will refresh the WebGLTexture from the Canvas source. Only call this if you know that the
* canvas has changed, as there is a significant GPU texture allocation cost involved in doing so.
*
* @method Phaser.Textures.CanvasTexture#refresh
2018-05-04 17:51:02 +00:00
* @since 3.7.0
2018-04-23 17:37:44 +00:00
*
* @return {Phaser.Textures.CanvasTexture} This CanvasTexture.
*/
refresh: function ()
{
this._source.update();
2018-04-23 17:37:44 +00:00
return this;
},
/**
* Gets the Canvas Element.
2018-04-23 17:37:44 +00:00
*
* @method Phaser.Textures.CanvasTexture#getCanvas
2018-05-04 17:51:02 +00:00
* @since 3.7.0
2018-04-23 17:37:44 +00:00
*
* @return {HTMLCanvasElement} The Canvas DOM element this texture is using.
*/
getCanvas: function ()
{
return this.canvas;
},
/**
* Gets the 2D Canvas Rendering Context.
2018-04-23 17:37:44 +00:00
*
* @method Phaser.Textures.CanvasTexture#getContext
2018-05-04 17:51:02 +00:00
* @since 3.7.0
2018-04-23 17:37:44 +00:00
*
* @return {CanvasRenderingContext2D} The Canvas Rendering Context this texture is using.
2018-04-23 17:37:44 +00:00
*/
getContext: function ()
{
return this.context;
},
/**
* Clears this Canvas Texture, resetting it back to transparent.
*
* @method Phaser.Textures.CanvasTexture#clear
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*
* @return {Phaser.Textures.CanvasTexture} The Canvas Texture.
*/
clear: function ()
{
this.context.clearRect(0, 0, this.width, this.height);
2018-09-10 19:44:19 +00:00
return this.update();
},
/**
* Changes the size of this Canvas Texture.
*
* @method Phaser.Textures.CanvasTexture#setSize
2018-05-04 17:51:02 +00:00
* @since 3.7.0
*
* @param {integer} width - The new width of the Canvas.
* @param {integer} [height] - The new height of the Canvas. If not given it will use the width as the height.
*
* @return {Phaser.Textures.CanvasTexture} The Canvas Texture.
*/
setSize: function (width, height)
{
if (height === undefined) { height = width; }
if (width !== this.width || height !== this.height)
{
// Update the Canvas
this.canvas.width = width;
this.canvas.height = height;
// Update the Texture Source
this._source.width = width;
this._source.height = height;
this._source.isPowerOf2 = IsSizePowerOfTwo(width, height);
// Update the Frame
this.frames['__BASE'].setSize(width, height, 0, 0);
this.refresh();
}
return this;
}
2018-04-23 17:37:44 +00:00
});
module.exports = CanvasTexture;