phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
297 lines (267 loc) • 10 kB
JavaScript
/**
* @author Richard Davey <rich@phaser.io>
* @author Felipe Alfonso <@bitnenfer>
* @author Matthew Groves <@doormat>
* @copyright 2013-2026 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var TransformMatrix = require('../../gameobjects/components/TransformMatrix');
/**
* @namespace Phaser.Renderer.WebGL.Utils
* @since 3.0.0
*/
module.exports = {
/**
* Packs four floats in a range from 0.0 to 1.0 into a single Uint32
*
* @function Phaser.Renderer.WebGL.Utils.getTintFromFloats
* @since 3.0.0
*
* @param {number} r - Red component in a range from 0.0 to 1.0
* @param {number} g - Green component in a range from 0.0 to 1.0
* @param {number} b - Blue component in a range from 0.0 to 1.0
* @param {number} a - Alpha component in a range from 0.0 to 1.0
*
* @return {number} The packed RGBA values as a Uint32.
*/
getTintFromFloats: function (r, g, b, a)
{
var ur = ((r * 255) | 0) & 0xff;
var ug = ((g * 255) | 0) & 0xff;
var ub = ((b * 255) | 0) & 0xff;
var ua = ((a * 255) | 0) & 0xff;
return ((ua << 24) | (ur << 16) | (ug << 8) | ub) >>> 0;
},
/**
* Packs a Uint24, representing RGB components, with a Float32, representing
* the alpha component, with a range between 0.0 and 1.0 and returns a Uint32
*
* @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlpha
* @since 3.0.0
*
* @param {number} rgb - Uint24 representing RGB components
* @param {number} a - Float32 representing Alpha component
*
* @return {number} Packed RGBA as Uint32
*/
getTintAppendFloatAlpha: function (rgb, a)
{
var ua = ((a * 255) | 0) & 0xff;
return ((ua << 24) | rgb) >>> 0;
},
/**
* Packs a Uint24, representing RGB components, with a Float32, representing
* the alpha component, with a range between 0.0 and 1.0 and returns a
* swizzled Uint32 with the red and blue channels exchanged (RGB becomes BGR)
*
* @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlphaAndSwap
* @since 3.0.0
*
* @param {number} rgb - Uint24 representing RGB components
* @param {number} a - Float32 representing Alpha component
*
* @return {number} Packed RGBA as Uint32
*/
getTintAppendFloatAlphaAndSwap: function (rgb, a)
{
var ur = ((rgb >> 16) | 0) & 0xff;
var ug = ((rgb >> 8) | 0) & 0xff;
var ub = (rgb | 0) & 0xff;
var ua = ((a * 255) | 0) & 0xff;
return ((ua << 24) | (ub << 16) | (ug << 8) | ur) >>> 0;
},
/**
* Unpacks a Uint24 RGB into an array of floats with values in the range 0.0 to 1.0
*
* @function Phaser.Renderer.WebGL.Utils.getFloatsFromUintRGB
* @since 3.0.0
*
* @param {number} rgb - RGB packed as a Uint24
*
* @return {array} Array of floats representing each component as a float
*/
getFloatsFromUintRGB: function (rgb)
{
var ur = ((rgb >> 16) | 0) & 0xff;
var ug = ((rgb >> 8) | 0) & 0xff;
var ub = (rgb | 0) & 0xff;
return [ ur / 255, ug / 255, ub / 255 ];
},
/**
* Check to see how many texture units the GPU supports in a fragment shader
* and if the value specified in the game config is allowed.
*
* This value is hard-clamped to 16 for performance reasons on Android devices.
*
* @function Phaser.Renderer.WebGL.Utils.checkShaderMax
* @since 3.50.0
*
* @param {WebGLRenderingContext} gl - The WebGLContext used to create the shaders.
* @param {number} maxTextures - The Game Config maxTextures value.
*
* @return {number} The number of texture units that is supported by this browser and GPU.
*/
checkShaderMax: function (gl, maxTextures)
{
// Note: This is the maximum number of TIUs that a _fragment_ shader supports
// https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_Unit
// Hard-clamp this to 16 to avoid run-away texture counts such as on Android
var gpuMax = Math.min(16, gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
if (!maxTextures || maxTextures === -1)
{
return gpuMax;
}
else
{
return Math.min(gpuMax, maxTextures);
}
},
/**
* Sets or clears all lighting-related uniforms on the given shader program manager.
*
* When `enable` is `true`, this function queries the Scene's Light Manager for all
* active lights visible to the camera and uploads their positions, colors, intensities,
* and radii as uniform arrays to the shader. It also uploads the ambient light color,
* camera transform, and the normal map texture unit. Optionally enables self-shadowing
* by uploading the penumbra and diffuse threshold uniforms.
*
* When `enable` is `false`, all previously set lighting uniforms are removed from the
* program manager. If the Scene has no active Light Manager, the function returns early
* without making any changes.
*
* @function Phaser.Renderer.WebGL.Utils.updateLightingUniforms
* @since 4.0.0
* @webglOnly
*
* @param {boolean} enable - Whether to enable lighting.
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The DrawingContext instance.
* @param {Phaser.Renderer.WebGL.ProgramManager} programManager - The ShaderProgramManager instance.
* @param {number} textureUnit - The texture unit to use for the normal map.
* @param {Phaser.Math.Vector2} vec - A Vector2 instance.
* @param {boolean} [selfShadow] - Whether to enable self-shadowing.
* @param {number} [selfShadowPenumbra] - The penumbra value for self-shadowing.
* @param {number} [selfShadowThreshold] - The threshold value for self-shadowing.
*/
updateLightingUniforms: function (
enable,
drawingContext,
programManager,
textureUnit,
vec,
selfShadow,
selfShadowPenumbra,
selfShadowThreshold
)
{
var camera = drawingContext.camera;
var scene = camera.scene;
var lightManager = scene.sys.lights;
if (!lightManager || !lightManager.active)
{
return;
}
var lights = lightManager.getLights(camera);
var lightsCount = lights.length;
var ambientColor = lightManager.ambientColor;
var height = drawingContext.height;
if (enable)
{
programManager.setUniform(
'uNormSampler',
textureUnit
);
programManager.setUniform(
'uCamera',
[
camera.x,
camera.y,
camera.rotation,
camera.zoom
]
);
programManager.setUniform(
'uAmbientLightColor',
[
ambientColor.r,
ambientColor.g,
ambientColor.b
]
);
programManager.setUniform(
'uLightCount',
lightsCount
);
var camMatrix = new TransformMatrix();
for (var i = 0; i < lightsCount; i++)
{
var light = lights[i].light;
var color = light.color;
var lightName = 'uLights[' + i + '].';
camMatrix.copyWithScrollFactorFrom(
camera.matrixCombined,
camera.scrollX, camera.scrollY,
light.scrollFactorX, light.scrollFactorY
);
camMatrix.transformPoint(
light.x,
light.y,
vec
);
programManager.setUniform(
lightName + 'position',
[
vec.x,
height - (vec.y),
light.z * camera.zoom
]
);
programManager.setUniform(
lightName + 'color',
[
color.r,
color.g,
color.b
]
);
programManager.setUniform(
lightName + 'intensity',
light.intensity
);
programManager.setUniform(
lightName + 'radius',
light.radius
);
}
if (selfShadow)
{
// Self-shadowing uniforms.
programManager.setUniform(
'uDiffuseFlatThreshold',
selfShadowThreshold * 3
);
programManager.setUniform(
'uPenumbra',
selfShadowPenumbra
);
}
}
else
{
// Clear lighting uniforms.
programManager.removeUniform('uNormSampler');
programManager.removeUniform('uCamera');
programManager.removeUniform('uAmbientLightColor');
programManager.removeUniform('uLightCount');
programManager.removeUniform('uPenumbra');
programManager.removeUniform('uDiffuseFlatThreshold');
for (i = 0; i < lightsCount; i++)
{
lightName = 'uLights[' + i + '].';
programManager.removeUniform(lightName + 'position');
programManager.removeUniform(lightName + 'color');
programManager.removeUniform(lightName + 'intensity');
programManager.removeUniform(lightName + 'radius');
}
}
}
};