UNPKG

@absulit/points

Version:

A Generative Art library made in WebGPU

220 lines (191 loc) 5.84 kB
import { isArray } from './data-size.js'; /** * Uniform is a container for uniform buffer related data and actions. * * @class Uniform */ class Uniform { #name #value #type #size /** * * @param {{name:String, value:(Number|Boolean|Array<Number>), type:string, size:Number=}} config */ constructor({ name, value, type = null, size = null }) { this.#validateName(name); this.#validateType(type); this.#validateValue(value); this.#name = name; this.#value = value; this.#type = type || this.#getArrayType(value) || 'f32'; this.#size = size; Object.seal(this); } get name() { return this.#name; } /** * The name that the Uniform will have on the WGSL side. * @param {String} value name of the Uniform. The name is used in the WGSL * shader. * @example * // js * myUniform.name = 'myUniformName'; * * // wgsl * myUniformName = 13.0; * @memberof Uniform */ set name(value) { this.#validateName(value); this.#name = value; } get value() { return this.#value; } /** * To get or set the value of the uniform from the JS side to the WGSL side. * @param {Number|Boolean|Array<Number>} value The uniform value * @memberof Uniform */ set value(value) { this.#validateValue(value); this.#value = value; } get type() { return this.#type } /** * Get or set the type of the uniform. * It can be inferred automatically by just passing the value, but if * something more specific is required, then you should use `type`. * @param {String} value WGSL data type of the uniform * @example * myUniform.type = 'u32'; * @memberof Uniform */ set type(value) { this.#validateType(value); this.#type = value || this.#getArrayType(this.#value) || 'f32'; } get size() { return this.#size; } /** * For internal use mostly. Size in bytes. * @memberof Uniform */ set size(value) { this.#size = value; } /** * Clone of the Uniform data as a plain object to avoid modifications on * the original data. * @returns {Object} * @memberof Uniform */ serialize() { // we check if array and spread // because structuredClone is slower const isArray = Array.isArray(this.#value); const value = isArray ? [...this.#value] : this.#value; return { name: this.#name, value, type: this.#type, size: this.#size }; } /** * Sets or updates the value of the Uniform. * @param {Number|Boolean|Array<Number>} value * @memberof Uniform */ setValue(value) { this.#validateValue(value); this.#value = value; return this; } /** * Set the data type of the uniform. * @param {String} value WGSL data type of the uniform * @example * myUniform.setType('u32') * @memberof Uniform */ setType(value) { this.#validateType(value); this.#type = value || this.#getArrayType(this.#value) || 'f32'; return this; } #validateValue(value) { if (typeof value === 'object' && !Array.isArray(value)) { throw `Uniform '${this.#name}' value:'${value}' can't be an Object.` } if (typeof value === 'string') { throw `Uniform '${this.#name}' value: '${value}' can't be an String.` } const isArray = Array.isArray(value); if (isArray) { const { length } = value; // TODO include mat values, e.g.: mat4x2 // if (length > 4) { // console.trace(this.#name, this.#value); // throw `Uniform named '${this.#name}': Can't assign an Array greater than a vec4f.` // } if (Array.isArray(this.#value)) { if (length != this.#value.length) { throw `Uniform named '${this.#name}': Size of the array value has changed from ${this.#value.length} to ${length}.` } } if (length < 2) { throw `Uniform named '${this.#name}': Can't assign an Array smaller than a vec2f. Assign the Number directly.` } } } #validateName(value) { if (typeof value === 'number') { throw `Uniform name '${this.#name}' can't be an Number.` } if (typeof value === 'string') { const valNumber = +value; if (!Number.isNaN(valNumber) && typeof valNumber === 'number') { throw `Uniform name '${this.#name}' can't be an Number.` } } } #validateType(value) { if (value && isArray(value)) { throw `Uniform '${this.#name}' type: '${value}' is an array, which is currently not supported for Uniforms.`; } } /** * There's already a `getArrayType` in data-size.js * but since uniforms can't accept array in wgsl, * this method excludes that part * returns something like vec2f, vec3f * @param {Array|Object} value * @returns {String} */ #getArrayType(value) { const isArray = Array.isArray(value); let type = null; if (isArray) { const { length } = value if (length <= 4) { type = `vec${length}f`; } } return type; } // allows for things like: // uniforms.myUniform += 10 // works on set, not on get // on get you obtain the Uniform valueOf() { return this.#value; } } export default Uniform;