@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
177 lines (145 loc) • 4.47 kB
JavaScript
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;