UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

177 lines (145 loc) 4.47 kB
import { assert } from "../../../core/assert.js"; import { BinaryDataType } from "../../../core/binary/type/BinaryDataType.js"; import { DataTypeByteSizes } from "../../../core/binary/type/DataTypeByteSizes.js"; import { objectKeyByValue } from "../../../core/model/object/objectKeyByValue.js"; import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js"; /** * Describes data structure of a single data attribute, such as a scalar, or a vector * This structure is designed to map well to GPU shader formats and is intended for larger datasets, such as meshes or particle clouds */ export class AttributeSpec { /** * Typically unique within a given set, used to identify the attribute * @type {string} */ name = ""; // TODO move out into attribute /** * How the attribute is stored in memory and interpreted * @type {BinaryDataType} */ type = BinaryDataType.Float32; /** * How many elements the attribute uses. This is cardinality of a vector. * 1 means the attribute is a scalar * must be greater or equal to 1 * @type {number} */ itemSize = 1; /** * Normalized values will be automatically converted to float32 in the shader * This gives good optimization opportunities for things like normal vectors * Applies to integer types only * @type {boolean} */ normalized = false; /** * Utility constructor * @param {BinaryDataType} type * @param {number} itemSize * @param {boolean} [normalized] * @param {string} [name] * @returns {AttributeSpec} */ static from(type, itemSize, normalized = false, name = "") { const spec = new AttributeSpec(); spec.fromJSON({ name, type, itemSize, normalized }); return spec; } static fromJSON(j) { const r = new AttributeSpec(); r.fromJSON(j); return r; } fromJSON({ name = "", type, itemSize, normalized = false }) { assert.isString(name, 'name'); assert.enum(type, BinaryDataType, 'type'); assert.isNumber(itemSize, 'itemSize'); assert.isNonNegativeInteger(itemSize, 'itemSize'); assert.greaterThanOrEqual(itemSize, 1, 'itemSize must be >= 1'); assert.isBoolean(normalized, 'normalized'); this.name = name; this.type = type; this.itemSize = itemSize; this.normalized = normalized; } toJSON() { return { name: this.name, type: this.type, itemSize: this.itemSize, normalized: this.normalized }; } toString() { let r = ''; if (this.name !== "") { r += `${this.name}:` } r += `${this.itemSize}x${( objectKeyByValue(BinaryDataType, this.type) ?? this.type)}`; if (this.normalized) { r += '-norm'; } return r; } hash() { return computeStringHash(this.name); } /** * * @param {AttributeSpec} other * @returns {boolean} */ equals(other) { return this.type === other.type && this.itemSize === other.itemSize && this.normalized === other.normalized && this.name === other.name ; } /** * * @param {AttributeSpec} other */ copy(other) { this.type = other.type; this.name = other.name; this.itemSize = other.itemSize; this.normalized = other.normalized; } clone() { const r = new AttributeSpec(); r.copy(this); return r; } /** * How much space a single attribute value takes up * @returns {number} in bytes */ getByteSize() { return this.itemSize * DataTypeByteSizes[this.type]; } /** * Sorting comparator * @param {AttributeSpec} a * @param {AttributeSpec} b * @return {number} */ static byName(a, b) { return a.name.localeCompare(b.name); } } /** * @readonly * @type {boolean} */ AttributeSpec.prototype.isAttributeSpec = true;