// luma.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import type {VariableShaderType} from '../shadertypes/shader-types/shader-types'; import type {UniformValue} from '../adapter/types/uniforms'; import { ShaderLayout, UniformInfo, UniformBufferBindingLayout } from '../adapter/types/shader-layout'; import {arrayEqual, arrayCopy} from '../utils/array-equal'; /** * A uniform block holds values of the of uniform values for one uniform block / buffer. * It also does some book keeping on what has changed, to minimize unnecessary writes to uniform buffers. */ export class UniformBlock< TUniforms extends Record = Record > { name: string; uniforms: Record = {} as Record; modifiedUniforms: Record = {} as Record; modified: boolean = true; readonly bindingLayout: Record = {}; needsRedraw: string | false = 'initialized'; constructor(props?: { name?: string; shaderLayout?: ShaderLayout; uniformTypes?: Record>; }) { this.name = props?.name || 'unnamed'; // TODO - Extract uniform layout from the shaderLayout object if (props?.name && props?.shaderLayout) { const binding = props?.shaderLayout.bindings?.find( binding_ => binding_.type === 'uniform' && binding_.name === props?.name ); if (!binding) { throw new Error(props?.name); } const uniformBlock = binding as UniformBufferBindingLayout; for (const uniform of uniformBlock.uniforms || []) { this.bindingLayout[uniform.name] = uniform; } } } /** Set a map of uniforms */ setUniforms(uniforms: Partial): void { for (const [key, value] of Object.entries(uniforms)) { this._setUniform(key, value); if (!this.needsRedraw) { this.setNeedsRedraw(`${this.name}.${key}=${value}`); } } } setNeedsRedraw(reason: string): void { this.needsRedraw = this.needsRedraw || reason; } /** Returns all uniforms */ getAllUniforms(): Record { // @ts-expect-error this.modifiedUniforms = {}; this.needsRedraw = false; return (this.uniforms || {}) as Record; } /** Set a single uniform */ private _setUniform(key: keyof TUniforms, value: UniformValue) { if (arrayEqual(this.uniforms[key], value)) { return; } this.uniforms[key] = arrayCopy(value); this.modifiedUniforms[key] = true; this.modified = true; } }