Add RenderSteps component for customizing WebGL render steps.

This commit is contained in:
Ben Richards 2024-12-04 15:54:11 +13:00
parent 0a0aa0281d
commit 6a26ba011c
12 changed files with 201 additions and 9 deletions

View file

@ -5,6 +5,7 @@
*/ */
var Class = require('../utils/Class'); var Class = require('../utils/Class');
var Components = require('./components');
var ComponentsToJSON = require('./components/ToJSON'); var ComponentsToJSON = require('./components/ToJSON');
var DataManager = require('../data/DataManager'); var DataManager = require('../data/DataManager');
var EventEmitter = require('eventemitter3'); var EventEmitter = require('eventemitter3');
@ -30,6 +31,10 @@ var GameObject = new Class({
Extends: EventEmitter, Extends: EventEmitter,
Mixins: [
Components.RenderSteps,
],
initialize: initialize:
function GameObject (scene, type) function GameObject (scene, type)

View file

@ -0,0 +1,151 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2024 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* Handles render steps for a Game Object.
* The render step is a point in the render process that allows you to inject your own logic.
*
* @namespace Phaser.GameObjects.Components.RenderSteps
* @webglOnly
* @since 4.0.0
*/
var RenderSteps = {};
if (typeof WEBGL_RENDERER) RenderSteps = {
/**
* The list of steps to run when this Game Object is rendered.
* This is used by `renderWebGLStep` to kick off rendering.
* The functions in this list are responsible for invoking any
* subsequent functions.
*
* @name Phaser.GameObjects.Components.RenderSteps#_renderSteps
* @private
* @webglOnly
* @since 4.0.0
* @type {Phaser.Types.GameObjects.RenderWebGLStep[]}
*/
_renderSteps: null,
/**
* Run a step in the render process.
* This is called automatically by the Render module.
*
* In most cases, it just runs the `renderWebGL` function.
*
* When `_renderSteps` has more than one entry,
* such as when Filters are enabled for this object,
* it allows those processes to defer `renderWebGL`
* and otherwise manage the flow of rendering
*
* The first time this method is called,
* it will run initialization logic that adds `renderWebGL` to the end
* of the `_renderSteps` array.
* Then it will replace itself with `_renderWebGLStep`
* and continue with the rendering process.
*
* @method Phaser.GameObjects.GameObject#renderWebGLStep
* @webglOnly
* @since 4.0.0
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The WebGL Renderer instance to render with.
* @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered.
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentMatrix] - The parent matrix of the Game Object, if it has one.
* @param {number} [renderStep=0] - Which step of the rendering process should be run?
*/
renderWebGLStep: function (
renderer,
gameObject,
drawingContext,
parentMatrix,
renderStep
)
{
if (gameObject.renderWebGL)
{
gameObject.addRenderStep(gameObject.renderWebGL);
}
gameObject.renderWebGLStep = gameObject._renderWebGLStep;
gameObject._renderWebGLStep(
renderer,
gameObject,
drawingContext,
parentMatrix,
renderStep
);
},
/**
* Run a step in the render process.
* This is called automatically by the Render module.
*
* In most cases, it just runs the `renderWebGL` function.
*
* When `_renderSteps` has more than one entry,
* such as when Filters are enabled for this object,
* it allows those processes to defer `renderWebGL`
* and otherwise manage the flow of rendering.
*
* This private method will be copied over `renderWebGLStep`
* the first time it runs. You should not call this method directly.
*
* @method Phaser.GameObjects.GameObject#_renderWebGLStep
* @private
* @webglOnly
* @since 4.0.0
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The WebGL Renderer instance to render with.
* @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered.
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentMatrix] - The parent matrix of the Game Object, if it has one.
* @param {number} [renderStep=0] - Which step of the rendering process should be run?
*/
_renderWebGLStep: function (
renderer,
gameObject,
drawingContext,
parentMatrix,
renderStep
)
{
if (renderStep === undefined)
{
renderStep = 0;
}
var fn = gameObject._renderSteps[renderStep];
if (!fn)
{
return;
}
fn(renderer, gameObject, drawingContext, parentMatrix, renderStep);
},
addRenderStep: function (fn, index)
{
this.initRenderSteps();
if (index === undefined)
{
this._renderSteps.push(fn);
return;
}
this._renderSteps.splice(index, 0, fn);
},
initRenderSteps: function ()
{
if (!this._renderSteps)
{
this._renderSteps = [];
}
}
};
module.exports = RenderSteps;

View file

@ -25,6 +25,7 @@ module.exports = {
Origin: require('./Origin'), Origin: require('./Origin'),
PathFollower: require('./PathFollower'), PathFollower: require('./PathFollower'),
RenderNodes: require('./RenderNodes'), RenderNodes: require('./RenderNodes'),
RenderSteps: require('./RenderSteps'),
ScrollFactor: require('./ScrollFactor'), ScrollFactor: require('./ScrollFactor'),
Size: require('./Size'), Size: require('./Size'),
Texture: require('./Texture'), Texture: require('./Texture'),

View file

@ -118,7 +118,7 @@ var ContainerWebGLRenderer = function (renderer, container, drawingContext, pare
child.setAlpha(childAlphaTopLeft * alpha, childAlphaTopRight * alpha, childAlphaBottomLeft * alpha, childAlphaBottomRight * alpha); child.setAlpha(childAlphaTopLeft * alpha, childAlphaTopRight * alpha, childAlphaBottomLeft * alpha, childAlphaBottomRight * alpha);
// Render // Render
child.renderWebGL(renderer, child, currentContext, transformMatrix, container); child.renderWebGLStep(renderer, child, currentContext, transformMatrix);
// Restore original values // Restore original values

View file

@ -80,6 +80,7 @@ var Layer = new Class({
Components.BlendMode, Components.BlendMode,
Components.Depth, Components.Depth,
Components.Mask, Components.Mask,
Components.RenderSteps, // This does not extend GameObject so it must mixin RenderSteps here.
Components.Visible, Components.Visible,
EventEmitter, EventEmitter,
Render Render

View file

@ -92,7 +92,7 @@ var LayerWebGLRenderer = function (renderer, layer, drawingContext)
child.setAlpha(childAlphaTopLeft * alpha, childAlphaTopRight * alpha, childAlphaBottomLeft * alpha, childAlphaBottomRight * alpha); child.setAlpha(childAlphaTopLeft * alpha, childAlphaTopRight * alpha, childAlphaBottomLeft * alpha, childAlphaBottomRight * alpha);
// Render // Render
child.renderWebGL(renderer, child, currentContext); child.renderWebGLStep(renderer, child, currentContext);
// Restore original values // Restore original values
child.setAlpha(childAlphaTopLeft, childAlphaTopRight, childAlphaBottomLeft, childAlphaBottomRight); child.setAlpha(childAlphaTopLeft, childAlphaTopRight, childAlphaBottomLeft, childAlphaBottomRight);

View file

@ -386,7 +386,7 @@ var Shader = new Class({
this.renderToTexture = true; this.renderToTexture = true;
// Render at least once, so our texture isn't blank on the first update // Render at least once, so our texture isn't blank on the first update
this.renderWebGL(renderer, this, this.drawingContext); this.renderWebGLStep(renderer, this, this.drawingContext);
return this; return this;
}, },

View file

@ -0,0 +1,20 @@
/**
* A function which performs a rendering operation on the given Game Object.
* This is usually the `renderWebGL` method of the Game Object itself,
* but `Phaser.GameObjects.Components.RenderSteps` allows you to define
* a series of steps that are run in sequence.
* The function is not expected to run in any particular scope,
* so it should not use `this`. Instead, all required properties should be
* accessed via `gameObject`.
*
* @callback Phaser.Types.GameObjects.RenderWebGLStep
* @since 4.0.0
*
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - A reference to the current active WebGL renderer.
* @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered in this call.
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentMatrix] - This transform matrix is defined if the game object is nested
* @param {number} [renderStep=0] - The index of this function in the Game Object's list of render processes. Used to support multiple rendering functions.
*
* @returns {void}
*/

View file

@ -75,8 +75,16 @@ var Camera = new Class({
* @param {Phaser.Cameras.Scene2D.Camera} camera - Current Camera. * @param {Phaser.Cameras.Scene2D.Camera} camera - Current Camera.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentTransformMatrix] - This transform matrix is defined if the game object is nested * @param {Phaser.GameObjects.Components.TransformMatrix} [parentTransformMatrix] - This transform matrix is defined if the game object is nested
* @param {boolean} [forceFramebuffer=false] - Should the camera always draw to a new framebuffer? This will also be activated if the camera has filters enabled. * @param {boolean} [forceFramebuffer=false] - Should the camera always draw to a new framebuffer? This will also be activated if the camera has filters enabled.
* @param {number} [renderStep=0] - Which step of the rendering process is this? This is the index of the currently running function in a list of functions.
*/ */
run: function (drawingContext, children, camera, parentTransformMatrix, forceFramebuffer) run: function (
drawingContext,
children,
camera,
parentTransformMatrix,
forceFramebuffer,
renderStep
)
{ {
this.onRunBegin(drawingContext); this.onRunBegin(drawingContext);
@ -127,7 +135,7 @@ var Camera = new Class({
} }
// Draw children. // Draw children.
this.listCompositorNode.run(currentContext, children, useFramebuffers ? null : parentTransformMatrix); this.listCompositorNode.run(currentContext, children, useFramebuffers ? null : parentTransformMatrix, renderStep);
// Draw camera post effects. // Draw camera post effects.

View file

@ -307,7 +307,7 @@ var DynamicTextureHandler = new Class({
currentContext.use(); currentContext.use();
} }
object.renderWebGL(renderer, object, currentContext); object.renderWebGLStep(renderer, object, currentContext);
return currentContext; return currentContext;
} }

View file

@ -37,8 +37,14 @@ var ListCompositor = new Class({
* @param {Phaser.Renderer.WebGL.DrawingContext} displayContext - The context currently in use. * @param {Phaser.Renderer.WebGL.DrawingContext} displayContext - The context currently in use.
* @param {Phaser.GameObjects.GameObject[]} children - The list of children to render. * @param {Phaser.GameObjects.GameObject[]} children - The list of children to render.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentTransformMatrix] - This transform matrix is defined if the game object is nested * @param {Phaser.GameObjects.Components.TransformMatrix} [parentTransformMatrix] - This transform matrix is defined if the game object is nested
* @param {number} [renderStep=0] - Which step of the rendering process is this? This is the index of the currently running function in a list of functions.
*/ */
run: function (displayContext, children, parentTransformMatrix) run: function (
displayContext,
children,
parentTransformMatrix,
renderStep
)
{ {
this.onRunBegin(displayContext); this.onRunBegin(displayContext);
@ -79,7 +85,7 @@ var ListCompositor = new Class({
} }
} }
child.renderWebGL(renderer, child, currentContext, parentTransformMatrix); child.renderWebGLStep(renderer, child, currentContext, parentTransformMatrix, renderStep);
} }
// Release any remaining context. // Release any remaining context.

View file

@ -965,7 +965,7 @@ var DynamicTexture = new Class({
stamp.setTexture(this); stamp.setTexture(this);
stamp.setOrigin(0); stamp.setOrigin(0);
stamp.renderWebGL(renderer, stamp, camera, parentMatrix); stamp.renderWebGLStep(renderer, stamp, camera, parentMatrix);
}, },
/** /**