phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
411 lines (378 loc) • 13.1 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 DeepCopy = require('../../utils/object/DeepCopy');
/**
* @classdesc
* The ProgramManager is a utility class used to manage
* instantiated shader programs and a suite of associated data,
* such as a VAO. It maintains a shared pool of uniforms,
* so if a different shader program is used, the uniforms
* can be applied to the new program.
*
* @class ProgramManager
* @memberof Phaser.Renderer.WebGL
* @constructor
* @since 4.0.0
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The current WebGLRenderer instance.
* @param {Phaser.Types.Renderer.WebGL.WebGLAttributeBufferLayout[]} attributeBufferLayouts - The attribute buffer layouts to use in the program.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper} [indexBuffer] - The index buffer to use in the program, if any.
*/
var ProgramManager = new Class({
initialize: function ProgramManager (renderer, attributeBufferLayouts, indexBuffer)
{
/**
* The current WebGLRenderer instance.
*
* @name Phaser.Renderer.WebGL.ProgramManager#renderer
* @type {Phaser.Renderer.WebGL.WebGLRenderer}
* @since 4.0.0
*/
this.renderer = renderer;
/**
* The index buffer to use in the program, if any.
* This is used to create a VAO.
*
* @name Phaser.Renderer.WebGL.ProgramManager#indexBuffer
* @type {?Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper}
* @since 4.0.0
*/
this.indexBuffer = indexBuffer;
/**
* The attribute buffer layouts to use in the program.
* These are used to create a VAO.
*
* @name Phaser.Renderer.WebGL.ProgramManager#attributeBufferLayouts
* @type {Phaser.Types.Renderer.WebGL.WebGLAttributeBufferLayout[]}
* @since 4.0.0
*/
this.attributeBufferLayouts = attributeBufferLayouts;
/**
* The key of the currently active shader program.
*
* @name Phaser.Renderer.WebGL.ProgramManager#currentProgramKey
* @type {?string}
* @since 4.0.0
*/
this.currentProgramKey = null;
/**
* The configuration object currently being assembled.
*
* @name Phaser.Renderer.WebGL.ProgramManager#currentConfig
* @type {object}
* @since 4.0.0
*/
this.currentConfig = {
base: {
vertexShader: '',
fragmentShader: ''
},
additions: [],
features: []
};
/**
* A map of shader programs and associated data suite,
* identified by a unique key.
*
* Each key corresponds to an object of the following shape:
*
* - `program` (WebGLProgramWrapper) - The compiled shader program.
* - `vao` (WebGLVAOWrapper) - The VAO associated with the program.
* - `config` (object) - The configuration object used to create the program.
*
* @name Phaser.Renderer.WebGL.ProgramManager#programs
* @type {object}
* @since 4.0.0
*/
this.programs = {};
/**
* A map of uniform values, identified by the shader uniform names.
* This allows uniforms to be kept between shader programs.
*
* @name Phaser.Renderer.WebGL.ProgramManager#uniforms
* @type {object}
* @since 4.0.0
*/
this.uniforms = {};
},
/**
* Returns a program suite based on the current configuration.
* If the program does not exist, it is created.
*
* The suite contains the following properties:
*
* - `program` (WebGLProgramWrapper) - The compiled shader program.
* - `vao` (WebGLVAOWrapper) - The VAO associated with the program.
* - `config` (object) - The configuration object used to create the program.
*
* If parallel shader compilation is enabled,
* the program may not be available immediately.
* In this case, `null` is returned.
*
* @method Phaser.Renderer.WebGL.ProgramManager#getCurrentProgramSuite
* @since 4.0.0
* @return {?{ program: Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper, vao: Phaser.Renderer.WebGL.Wrappers.WebGLVAOWrapper, config: object }} The program suite, or `null` if the program is not available.
*/
getCurrentProgramSuite: function ()
{
var config = this.currentConfig;
var renderer = this.renderer;
var factory = renderer.shaderProgramFactory;
var key = factory.getKey(config.base, config.additions, config.features);
if (!this.programs[key])
{
var program = factory.getShaderProgram(config.base, config.additions, config.features);
if (program.compiling)
{
program.checkParallelCompile();
}
if (!program.compiling)
{
this.programs[key] = {
program: program,
vao: renderer.createVAO(
program,
this.indexBuffer,
this.attributeBufferLayouts
),
config: DeepCopy(config)
};
}
}
return this.programs[key] || null;
},
/**
* Resets the current configuration object to its default empty state,
* clearing the base vertex and fragment shaders, all shader additions,
* and all features.
*
* @method Phaser.Renderer.WebGL.ProgramManager#resetCurrentConfig
* @since 4.0.0
*/
resetCurrentConfig: function ()
{
this.currentConfig.base.vertexShader = '';
this.currentConfig.base.fragmentShader = '';
this.currentConfig.additions.length = 0;
this.currentConfig.features.length = 0;
},
/**
* Set the value of a uniform,
* available for all shader programs in this manager.
*
* @method Phaser.Renderer.WebGL.ProgramManager#setUniform
* @since 4.0.0
* @param {string} name - The name of the uniform.
* @param {any} value - The value of the uniform.
*/
setUniform: function (name, value)
{
this.uniforms[name] = value;
},
/**
* Delete a uniform value. While unused uniforms are not harmful,
* they do take time to process and can be a source of confusion.
*
* @method Phaser.Renderer.WebGL.ProgramManager#removeUniform
* @since 4.0.0
* @param {string} name - The name of the uniform.
*/
removeUniform: function (name)
{
delete this.uniforms[name];
},
/**
* Remove all uniforms.
*
* @method Phaser.Renderer.WebGL.ProgramManager#clearUniforms
* @since 4.0.0
*/
clearUniforms: function ()
{
this.uniforms = {};
},
/**
* Applies all stored uniform values to the given shader program.
* This is used to restore uniform state when switching between
* shader programs, ensuring the new program receives the same
* uniform values as the previous one.
*
* @method Phaser.Renderer.WebGL.ProgramManager#applyUniforms
* @since 4.0.0
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} program - The shader program to apply the uniforms to.
*/
applyUniforms: function (program)
{
var uniforms = this.uniforms;
for (var name in uniforms)
{
program.setUniform(name, uniforms[name]);
}
},
/**
* Set the base shader for the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#setBaseShader
* @since 4.0.0
* @param {string} name - The name of the shader program.
* @param {string} vertexShader - The vertex shader source code.
* @param {string} fragmentShader - The fragment shader source code.
*/
setBaseShader: function (name, vertexShader, fragmentShader)
{
var base = this.currentConfig.base;
base.name = name;
base.vertexShader = vertexShader;
base.fragmentShader = fragmentShader;
},
/**
* Add a shader addition to the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#addAddition
* @since 4.0.0
* @param {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig} addition - The shader addition to add.
* @param {number} [index] - The index at which to insert the addition. If not specified, it will be added at the end.
*/
addAddition: function (addition, index)
{
if (index === undefined)
{
this.currentConfig.additions.push(addition);
}
else
{
this.currentConfig.additions.splice(index, 0, addition);
}
},
/**
* Returns the addition with the given name.
*
* @method Phaser.Renderer.WebGL.ProgramManager#getAddition
* @since 4.0.0
* @param {string} name - The name to find.
* @return {?Phaser.Types.Renderer.WebGL.ShaderAdditionConfig} The addition, or `null` if it was not found.
*/
getAddition: function (name)
{
var additions = this.currentConfig.additions;
for (var i = 0; i < additions.length; i++)
{
var addition = additions[i];
if (addition.name === name)
{
return addition;
}
}
return null;
},
/**
* Returns a list of shader additions in the current config
* that have a specific tag.
*
* @method Phaser.Renderer.WebGL.ProgramManager#getAdditionsByTag
* @since 4.0.0
* @param {string} tag - The tag to filter by.
* @return {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig[]} The shader additions with the tag.
*/
getAdditionsByTag: function (tag)
{
return this.currentConfig.additions.filter(function (addition)
{
if (!addition.tags)
{
return false;
}
return addition.tags.includes(tag);
});
},
/**
* Returns the index of a shader addition with the given name.
*
* @method Phaser.Renderer.WebGL.ProgramManager#getAdditionIndex
* @since 4.0.0
* @param {string} name - The name to find.
* @return {number} The index of the addition, or `-1` if it was not found.
*/
getAdditionIndex: function (name)
{
return this.currentConfig.additions.findIndex(function (addition)
{
return addition.name === name;
});
},
/**
* Remove a shader addition from the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#removeAddition
* @since 4.0.0
* @param {string} name - The name of the shader addition to remove.
*/
removeAddition: function (name)
{
this.currentConfig.additions = this.currentConfig.additions.filter(function (addition)
{
return addition.name !== name;
});
},
/**
* Replace a shader addition in the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#replaceAddition
* @since 4.0.0
* @param {string} name - The name of the shader addition to replace.
* @param {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig} addition - The new shader addition.
*/
replaceAddition: function (name, addition)
{
var index = this.currentConfig.additions.findIndex(function (a)
{
return a.name === name;
});
if (index !== -1)
{
this.currentConfig.additions[index] = addition;
}
},
/**
* Add a feature to the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#addFeature
* @since 4.0.0
* @param {string} feature - The feature to add.
*/
addFeature: function (feature)
{
if (this.currentConfig.features.indexOf(feature) === -1)
{
this.currentConfig.features.push(feature);
}
},
/**
* Remove a feature from the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#removeFeature
* @since 4.0.0
* @param {string} feature - The feature to remove.
*/
removeFeature: function (feature)
{
this.currentConfig.features = this.currentConfig.features.filter(function (f)
{
return f !== feature;
});
},
/**
* Clear all features from the current configuration.
*
* @method Phaser.Renderer.WebGL.ProgramManager#clearFeatures
* @since 4.0.0
*/
clearFeatures: function ()
{
this.currentConfig.features.length = 0;
}
});
module.exports = ProgramManager;