phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
313 lines (281 loc) • 12.6 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 Class = require('../../../../utils/Class');
var Merge = require('../../../../utils/object/Merge');
var Utils = require('../../Utils.js');
var RenderNode = require('../RenderNode');
var getTint = Utils.getTintAppendFloatAlpha;
/**
* @classdesc
* The SubmitterQuad RenderNode submits data for rendering a single Image-like GameObject.
* It uses a BatchHandler to render the image as part of a batch.
*
* This node receives the drawing context, game object, and parent matrix.
* It also receives the texturer, tinter, and transformer nodes
* from the node that invoked it.
* This allows the behavior to be configured by setting the appropriate nodes
* on the GameObject for individual tweaks, or on the invoking Renderer node
* for global changes.
*
* @class SubmitterQuad
* @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 {Phaser.Types.Renderer.WebGL.RenderNodes.SubmitterQuadConfig} [config] - The configuration object for this RenderNode.
*/
var SubmitterQuad = new Class({
Extends: RenderNode,
initialize: function SubmitterQuad (manager, config)
{
config = Merge(config || {}, this.defaultConfig);
RenderNode.call(this, config.name, manager);
/**
* The key of the RenderNode used to render data.
*
* @name Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#batchHandler
* @type {string}
* @since 4.0.0
*/
this.batchHandler = config.batchHandler;
/**
* Persistent object reused to pass render options to the batch handler.
*
* @name Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#_renderOptions
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerQuadRenderOptions}
* @since 4.0.0
* @private
*/
this._renderOptions = {
multiTexturing: true,
lighting: null,
smoothPixelArt: null
};
/**
* Persistent object reused to pass lighting options to the batch handler.
*
* @name Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#_lightingOptions
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerQuadRenderOptionsLighting}
* @since 4.0.0
* @private
*/
this._lightingOptions = {
normalGLTexture: null,
normalMapRotation: 0,
selfShadow: {
enabled: false,
penumbra: 0,
diffuseFlatThreshold: 0
}
};
},
/**
* The default configuration for this RenderNode.
*
* @name Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#defaultConfig
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.SubmitterQuadConfig}
*/
defaultConfig: {
name: 'SubmitterQuad',
role: 'Submitter',
batchHandler: 'BatchHandler'
},
/**
* Processes the given GameObject and submits quad vertex data to the appropriate
* batch handler for rendering. This method invokes the texturer, transformer, and
* optional tinter nodes in sequence to compute texture coordinates, transformed
* vertex positions, and tint colors. If no tinter node is provided, Image-style
* tinting is read directly from the GameObject. It then calls `setRenderOptions`
* to resolve lighting and smooth pixel art settings before passing all assembled
* data to the batch handler.
*
* @method Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#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.GameObjects.Components.TransformMatrix} parentMatrix - The parent matrix of the GameObject.
* @param {?object} element - The specific element within the game object. This is used for objects that consist of multiple quads.
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode} texturerNode - The texturer node used to texture the GameObject. You may pass a TexturerImage node or an object containing equivalent data without a `run` method.
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode|{ quad: Float32Array }} transformerNode - The transformer node used to transform the GameObject. You may pass a transformer node or an object with a `quad` property.
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode|Omit<Phaser.Renderer.WebGL.RenderNodes.RenderNode, 'run'>} [tinterNode] - The tinter node used to tint the GameObject. You may pass a tinter node or an object containing equivalent data without a `run` method. If omitted, Image-style tinting will be used.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [normalMap] - The normal map texture to use for lighting. If omitted, the normal map texture of the GameObject will be used, or the default normal map texture of the renderer.
* @param {number} [normalMapRotation] - The rotation of the normal map texture. If omitted, the rotation of the GameObject will be used.
*/
run: function (
drawingContext,
gameObject,
parentMatrix,
element,
texturerNode,
transformerNode,
tinterNode,
normalMap,
normalMapRotation
)
{
this.onRunBegin(drawingContext);
var tintEffect, tintTopLeft, tintBottomLeft, tintTopRight, tintBottomRight;
if (texturerNode.run)
{
texturerNode.run(drawingContext, gameObject, element);
}
if (transformerNode.run)
{
transformerNode.run(drawingContext, gameObject, texturerNode, parentMatrix, element);
}
if (tinterNode)
{
if (tinterNode.run)
{
tinterNode.run(drawingContext, gameObject, element);
}
tintEffect = tinterNode.tintEffect;
tintTopLeft = tinterNode.tintTopLeft;
tintBottomLeft = tinterNode.tintBottomLeft;
tintTopRight = tinterNode.tintTopRight;
tintBottomRight = tinterNode.tintBottomRight;
}
else
{
tintEffect = gameObject.tintMode;
tintTopLeft = getTint(gameObject.tintTopLeft, gameObject._alphaTL);
tintBottomLeft = getTint(gameObject.tintBottomLeft, gameObject._alphaBL);
tintTopRight = getTint(gameObject.tintTopRight, gameObject._alphaTR);
tintBottomRight = getTint(gameObject.tintBottomRight, gameObject._alphaBR);
}
var quad = transformerNode.quad;
var uvSource = texturerNode.uvSource;
var u0 = uvSource.u0;
var v0 = uvSource.v0;
var u1 = uvSource.u1;
var v1 = uvSource.v1;
this.setRenderOptions(gameObject, normalMap, normalMapRotation);
(
gameObject.customRenderNodes[this.batchHandler] ||
gameObject.defaultRenderNodes[this.batchHandler]
).batch(
drawingContext,
// Use `frame.source.glTexture` instead of `frame.glTexture`
// to avoid unnecessary getter function calls.
texturerNode.frame.source.glTexture,
// Transformed quad in order TL, BL, TR, BR:
quad[0], quad[1],
quad[2], quad[3],
quad[6], quad[7],
quad[4], quad[5],
// Texture coordinates in X, Y, Width, Height:
u0, v0, u1 - u0, v1 - v0,
tintEffect,
// Tint colors in order TL, BL, TR, BR:
tintTopLeft, tintBottomLeft, tintTopRight, tintBottomRight,
// Extra render options:
this._renderOptions
);
this.onRunEnd(drawingContext);
},
/**
* Resolves and stores render options for the current GameObject into `_renderOptions`
* before it is submitted to the batch handler. This includes determining the correct
* normal map texture and rotation for lighting (falling back to the game object's base
* texture data source, then the renderer's default normal texture), resolving self-shadow
* settings (falling back to the global game configuration if not set on the object), and
* determining the smooth pixel art setting from either the base texture or the global
* game configuration. If the GameObject has no lighting component, the lighting option
* is set to `null`.
*
* @method Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad#setRenderOptions
* @since 4.0.0
* @param {Phaser.GameObjects.GameObject} gameObject - The GameObject being rendered.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [normalMap] - The normal map texture to use for lighting. If omitted, it will be resolved from the game object's base texture data source or the renderer's default normal texture.
* @param {number} [normalMapRotation] - The rotation of the normal map texture, in radians. If omitted or `NaN`, it will be resolved from the game object's rotation or its world transform matrix if it belongs to a container.
*/
setRenderOptions: function (gameObject, normalMap, normalMapRotation)
{
var renderOptions = this._renderOptions;
var baseTexture, sourceIndex;
if (gameObject.displayTexture)
{
baseTexture = gameObject.displayTexture;
sourceIndex = gameObject.displayFrame.sourceIndex;
}
else if (gameObject.texture)
{
baseTexture = gameObject.texture;
sourceIndex = gameObject.frame.sourceIndex;
}
else if (gameObject.tileset)
{
if (Array.isArray(gameObject.tileset))
{
baseTexture = gameObject.tileset[0].image;
}
else
{
baseTexture = gameObject.tileset.image;
}
sourceIndex = 0;
}
if (gameObject.lighting)
{
// Get normal map.
if (!normalMap)
{
if (baseTexture)
{
normalMap = baseTexture.dataSource[sourceIndex];
}
}
if (!normalMap)
{
normalMap = this.manager.renderer.normalTexture;
}
else
{
normalMap = normalMap.glTexture;
}
// Get normal map rotation.
if (isNaN(normalMapRotation))
{
normalMapRotation = gameObject.rotation;
if (gameObject.parentContainer)
{
var matrix = gameObject.getWorldTransformMatrix(this._tempMatrix, this._tempMatrix2);
normalMapRotation = matrix.rotationNormalized;
}
}
// Get self-shadow.
var selfShadow = gameObject.selfShadow;
var selfShadowEnabled = selfShadow.enabled;
if (selfShadowEnabled === null)
{
selfShadowEnabled = gameObject.scene.sys.game.config.selfShadow;
}
this._lightingOptions.normalGLTexture = normalMap;
this._lightingOptions.normalMapRotation = normalMapRotation;
this._lightingOptions.selfShadow.enabled = selfShadowEnabled;
this._lightingOptions.selfShadow.penumbra = selfShadow.penumbra;
this._lightingOptions.selfShadow.diffuseFlatThreshold = selfShadow.diffuseFlatThreshold;
renderOptions.lighting = this._lightingOptions;
}
else
{
renderOptions.lighting = null;
}
// Get smooth pixel art option.
var smoothPixelArt;
if (baseTexture && baseTexture.smoothPixelArt !== null)
{
smoothPixelArt = baseTexture.smoothPixelArt;
}
else
{
smoothPixelArt = gameObject.scene.sys.game.config.smoothPixelArt;
}
renderOptions.smoothPixelArt = smoothPixelArt;
}
});
module.exports = SubmitterQuad;