phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
203 lines (174 loc) • 7.66 kB
JavaScript
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2026 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var TransformMatrix = require('../../../../gameobjects/components/TransformMatrix.js');
var Class = require('../../../../utils/Class');
var Merge = require('../../../../utils/object/Merge');
var RenderNode = require('../RenderNode');
/**
* @classdesc
* A RenderNode that computes and stores the screen-space quad vertex positions
* for a single Image-like GameObject each time it is rendered.
*
* During its `run` call, this node combines the camera view matrix (adjusted
* for the game object's scroll factors), any parent container matrix, and the
* game object's own position, rotation, and scale into a single final transform
* matrix. It then projects the four corners of the game object's frame through
* that matrix and writes the resulting eight coordinate values (four x/y pairs)
* into the `quad` Float32Array, ready for consumption by the subsequent
* submitter node.
*
* Horizontal and vertical flipping are handled here, with the local origin
* offset adjusted automatically when the frame does not use a custom pivot.
* Vertex rounding is also applied when required by the game object or camera
* settings, snapping all quad corners to integer pixel coordinates to avoid
* sub-pixel rendering artefacts.
*
* @class TransformerImage
* @memberof Phaser.Renderer.WebGL.RenderNodes
* @constructor
* @since 4.0.0
* @extends Phaser.Renderer.WebGL.RenderNodes.RenderNode
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
* @param {object} [config] - The configuration object for this RenderNode.
*/
var TransformerImage = new Class({
Extends: RenderNode,
initialize: function TransformerImage (manager, config)
{
config = Merge(config || {}, this.defaultConfig);
RenderNode.call(this, config.name, manager);
/**
* A flat array of 8 floats storing the screen-space positions of the four
* corners of the rendered quad, written during each `run` call. Values are
* ordered as [x0, y0, x1, y1, x2, y2, x3, y3], representing the top-left,
* top-right, bottom-left, and bottom-right corners respectively.
*
* @name Phaser.Renderer.WebGL.RenderNodes.TransformerImage#quad
* @type {Float32Array}
* @since 4.0.0
*/
this.quad = new Float32Array(8);
/**
* The matrix used internally to compute sprite transforms.
*
* @name Phaser.Renderer.WebGL.RenderNodes.TransformerImage#_spriteMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @since 4.0.0
* @private
*/
this._spriteMatrix = new TransformMatrix();
/**
* The matrix used internally to compute the final transform.
*
* @name Phaser.Renderer.WebGL.RenderNodes.TransformerImage#_calcMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @since 4.0.0
* @private
*/
this._calcMatrix = new TransformMatrix();
},
defaultConfig: {
name: 'TransformerImage',
role: 'Transformer'
},
/**
* Computes the final screen-space quad vertex positions for the given
* Image-like GameObject and stores them in `this.quad`.
*
* The method builds the complete transform by combining the camera view
* matrix (modified by the game object's scroll factors), an optional parent
* container matrix, and the game object's own position, rotation, and scale.
* Horizontal and vertical flips are factored in by negating the relevant
* scale axis and, when the frame does not use a custom pivot, by adjusting
* the local origin offset so the image flips around its display origin.
* The resulting four corner positions are then projected through the matrix
* via `setQuad` and written into `this.quad`. If vertex rounding is required,
* all eight values are snapped to the nearest integer before the node exits.
*
* @method Phaser.Renderer.WebGL.RenderNodes.TransformerImage#run
* @since 4.0.0
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
* @param {Phaser.GameObjects.GameObject} gameObject - The GameObject being rendered.
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode} texturerNode - The texturer node used to texture the GameObject. This contains relevant data on the dimensions of the object.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentMatrix] - This transform matrix is defined if the game object is nested.
* @param {object} [element] - The specific element within the game object. This is used for objects that consist of multiple quads. It is unused here.
*/
run: function (drawingContext, gameObject, texturerNode, parentMatrix, element)
{
this.onRunBegin(drawingContext);
var frame = texturerNode.frame;
var uvSource = texturerNode.uvSource;
var frameX = uvSource.x;
var frameY = uvSource.y;
var displayOriginX = gameObject.displayOriginX;
var displayOriginY = gameObject.displayOriginY;
var x = -displayOriginX + frameX;
var y = -displayOriginY + frameY;
var customPivot = frame.customPivot;
var flipX = 1;
var flipY = 1;
if (gameObject.flipX)
{
if (!customPivot)
{
x += (-frame.realWidth + (displayOriginX * 2));
}
flipX = -1;
}
if (gameObject.flipY)
{
if (!customPivot)
{
y += (-frame.realHeight + (displayOriginY * 2));
}
flipY = -1;
}
var camera = drawingContext.camera;
var spriteMatrix = this._spriteMatrix;
var calcMatrix = this._calcMatrix.copyWithScrollFactorFrom(
camera.getViewMatrix(!drawingContext.useCanvas),
camera.scrollX, camera.scrollY,
gameObject.scrollFactorX, gameObject.scrollFactorY
);
if (parentMatrix)
{
calcMatrix.multiply(parentMatrix);
}
spriteMatrix.applyITRS(
gameObject.x, gameObject.y,
gameObject.rotation,
gameObject.scaleX * flipX, gameObject.scaleY * flipY
);
calcMatrix.multiply(spriteMatrix);
// Store the output quad.
calcMatrix.setQuad(
x,
y,
x + texturerNode.frameWidth,
y + texturerNode.frameHeight,
this.quad
);
// Determine whether the matrix does not rotate, scale, or skew.
// Keyword: #OnlyTranslate
var cmm = calcMatrix.matrix;
var onlyTranslate = cmm[0] === 1 && cmm[1] === 0 && cmm[2] === 0 && cmm[3] === 1;
// Handle vertex rounding.
if (gameObject.willRoundVertices(camera, onlyTranslate))
{
var quad = this.quad;
quad[0] = Math.round(quad[0]);
quad[1] = Math.round(quad[1]);
quad[2] = Math.round(quad[2]);
quad[3] = Math.round(quad[3]);
quad[4] = Math.round(quad[4]);
quad[5] = Math.round(quad[5]);
quad[6] = Math.round(quad[6]);
quad[7] = Math.round(quad[7]);
}
this.onRunEnd(drawingContext);
}
});
module.exports = TransformerImage;