UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

236 lines (202 loc) 8.58 kB
/** * @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'); /** * @typedef {object} BaseShaderConfig * @property {string} name - The name of the shader program, used as a key. * @property {string} vertexShader - The vertex shader source code. * @property {string} fragmentShader - The fragment shader source code. */ /** * @classdesc * The ShaderProgramFactory is a utility class used to create and cache * {@link Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} objects for the * WebGL renderer. It assembles compiled shader programs from a base shader * combined with optional additions and feature flags, then stores the result * under a unique key so that the same combination is never compiled more than * once. Use this class when you need to obtain a shader program that may vary * at runtime based on renderer capabilities or pipeline configuration. * * @class ShaderProgramFactory * @memberof Phaser.Renderer.WebGL * @constructor * @since 4.0.0 * @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The WebGLRenderer that owns this ShaderProgramFactory. */ var ShaderProgramFactory = new Class({ initialize: function ShaderProgramFactory (renderer) { /** * The WebGLRenderer that owns this ShaderProgramFactory. * * @name Phaser.Renderer.WebGL.ShaderProgramFactory#renderer * @type {Phaser.Renderer.WebGL.WebGLRenderer} * @since 4.0.0 */ this.renderer = renderer; /** * A map of shader programs, identified by a unique key. * * The key of each shader program is made up of the following components: * * - The key of the base shader program. * - The key of each shader addition, in addition order. * - The key of each enabled shader feature, sorted alphabetically. * * @name Phaser.Renderer.WebGL.ShaderProgramFactory#programs * @type {object} * @since 4.0.0 */ this.programs = {}; }, /** * Checks whether a compiled shader program with the given key already exists * in the internal cache. * * @method Phaser.Renderer.WebGL.ShaderProgramFactory#has * @since 4.0.0 * @param {string} key - The unique key of the shader program. * @return {boolean} `true` if a shader program with this key exists in the cache, otherwise `false`. */ has: function (key) { return this.programs[key] !== undefined; }, /** * Returns a compiled shader program for the given configuration. If a * program matching the derived key already exists in the cache it is * returned immediately; otherwise a new program is compiled, stored in the * cache, and returned. * * @method Phaser.Renderer.WebGL.ShaderProgramFactory#getShaderProgram * @since 4.0.0 * @param {BaseShaderConfig} base - The base shader configuration. * @param {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig[]} [additions] - An array of shader addition configurations. * @param {string[]} [features] - An array of enabled shader feature keys. * @return {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} The compiled shader program wrapper. */ getShaderProgram: function (base, additions, features) { var key = this.getKey(base, additions, features); var program = this.programs[key]; if (!program) { program = this.createShaderProgram(key, base, additions, features); } return program; }, /** * Returns a unique key for a shader program based on the given configuration settings. * * The key is made up of the following components: * * - The key of the base shader program. * - The key of each shader addition, in addition order. * - The key of each enabled shader feature, sorted alphabetically. * * @method Phaser.Renderer.WebGL.ShaderProgramFactory#getKey * @since 4.0.0 * @param {BaseShaderConfig} base - The base shader configuration. * @param {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig[]} [additions] - An array of shader addition configurations. * @param {string[]} [features] - An array of enabled shader feature keys. * @return {string} The unique cache key for this shader configuration. */ getKey: function (base, additions, features) { var key = base.name; if (additions && additions.length > 0) { key += '_'; for (var i = 0; i < additions.length; i++) { var addition = additions[i]; if (!addition.disable) { key += '_' + addition.name; } } } if (features && features.length > 0) { key += '__'; key += features.sort().join('_'); } return key; }, /** * Creates a shader program based on the given configuration settings. * * @method Phaser.Renderer.WebGL.ShaderProgramFactory#createShaderProgram * @since 4.0.0 * @param {string} name - The unique key of the shader program. * @param {BaseShaderConfig} base - The base shader configuration. * @param {Phaser.Types.Renderer.WebGL.ShaderAdditionConfig[]} [additions] - An array of shader addition configurations. * @param {string[]} [features] - An array of enabled shader feature keys. * @return {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} The newly compiled and cached shader program wrapper. */ createShaderProgram: function (name, base, additions, features) { var vertexSource = base.vertexShader; var fragmentSource = base.fragmentShader; // Remove carriage return characters from the shader source. vertexSource = vertexSource.replace(/\r/g, ''); fragmentSource = fragmentSource.replace(/\r/g, ''); if (additions) { var key, value; var templates = {}; for (var i = 0; i < additions.length; i++) { var addition = additions[i]; if (addition.disable) { continue; } for (key in addition.additions) { value = addition.additions[key]; // Remove carriage return characters from the shader source. value = value.replace(/\r/g, ''); if (!templates[key]) { templates[key] = ''; } templates[key] += value + '\n'; } } for (key in templates) { var template = '#pragma phaserTemplate(' + key + ')\n'; value = templates[key]; vertexSource = vertexSource.replace(template, value); fragmentSource = fragmentSource.replace(template, value); } } if (features) { var featureDefines = ''; var reInvalid = /[^a-zA-Z0-9]/g; for (i = 0; i < features.length; i++) { var feature = features[i].toUpperCase().replace(reInvalid, '_'); featureDefines += '#define FEATURE_' + feature + '\n'; } vertexSource = vertexSource.replace('#pragma phaserTemplate(features)', featureDefines); fragmentSource = fragmentSource.replace('#pragma phaserTemplate(features)', featureDefines); } // Name the program after the key. vertexSource = vertexSource.replace('#pragma phaserTemplate(shaderName)', '#define SHADER_NAME ' + name + '__VERTEX'); fragmentSource = fragmentSource.replace('#pragma phaserTemplate(shaderName)', '#define SHADER_NAME ' + name + '__FRAGMENT'); // Remove any remaining template directives. var rePragma = /\s*#pragma phaserTemplate\(.*/g; vertexSource = vertexSource.replace(rePragma, ''); fragmentSource = fragmentSource.replace(rePragma, ''); var program = this.renderer.createProgram(vertexSource, fragmentSource); this.programs[name] = program; return program; } }); module.exports = ShaderProgramFactory;