@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
274 lines • 26 kB
JavaScript
export class TgdDataset {
constructor(attributesDefinition, options = {}) {
var _a, _b;
this.attributesDefinition = attributesDefinition;
this.options = options;
this.stride = 0;
this.definitions = {};
this._data = new ArrayBuffer(0);
this._count = 0;
this.target = (_a = options.target) !== null && _a !== void 0 ? _a : "ARRAY_BUFFER";
this.usage = (_b = options.usage) !== null && _b !== void 0 ? _b : "STATIC_DRAW";
this.initialize(attributesDefinition, options);
}
initialize(attributesDefinition, options = {}) {
var _a;
for (const name of Object.keys(attributesDefinition)) {
const definition = attributesDefinition[name];
this.attributesDefinition[name] = definition;
}
const divisor = (_a = options.divisor) !== null && _a !== void 0 ? _a : 0;
let stride = 0;
const data = {};
const definitions = {};
for (const name of Object.keys(attributesDefinition)) {
data[name] = new ArrayBuffer(0);
const definition = {
dimension: DIMS[attributesDefinition[name]],
byteOffset: stride,
bytesPerElement: Float32Array.BYTES_PER_ELEMENT,
divisor,
getter(view, byteOffset) {
if (byteOffset >= view.byteLength) {
byteOffset %= view.byteLength;
}
return view.getFloat32(byteOffset, true);
},
setter(view, byteOffset, value) {
view.setFloat32(byteOffset, value, true);
},
};
definitions[name] = definition;
stride += definition.bytesPerElement * definition.dimension;
}
this.definitions = definitions;
this.stride = stride;
this._data = resize(this._data, this.count * this.stride);
}
/**
* Throw an exception if the attribute `attribName` does not exist,
* or if it is not of any of the `types`.
* @param attribName
* @param types
*/
assertAttribType(attribName, ...types) {
const type = this.attributesDefinition[attribName];
if (!type)
throw new Error(`Attribute "${attribName}" does not exist! Available names are: ${Object.keys(this.attributesDefinition).join(", ")}.`);
if (!types.includes(type)) {
throw new Error(`Attribute "${attribName}" is of type "${type}", which is not ${types.join(" nor ")}!`);
}
return this;
}
addAttributes(attributesDefinition) {
const oldDataset = this.clone();
for (const key of Object.keys(attributesDefinition)) {
const oldType = this.attributesDefinition[key];
const newType = attributesDefinition[key];
if (oldType && oldType !== newType) {
throw new Error(`It is not allowed to change the type of attribute "${key}" from "${oldType}" to "${newType}"! Prefer removing the attribute first.`);
}
}
this.initialize(Object.assign(Object.assign({}, this.attributesDefinition), attributesDefinition), this.options);
// eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
const newDataset = this;
newDataset.count = oldDataset.count;
for (const attribName of oldDataset.attributesNames) {
try {
const { get } = oldDataset.getAttribAccessor(attribName);
const { set } = newDataset.getAttribAccessor(attribName);
for (let index = 0; index < oldDataset.count; index++) {
const definition = this.getDef(attribName);
for (let dim = 0; dim < definition.dimension; dim++) {
set(get(index, dim), index, dim);
}
}
}
catch (error) {
const message = error instanceof Error
? error.message
: JSON.stringify(error);
throw new Error(`Unable to clone attribute "${attribName}"!\n${message}`);
}
}
}
clone() {
const ds = new TgdDataset(structuredClone(this.attributesDefinition), this.options);
ds.count = this.count;
const source = new DataView(this._data);
const definition = new DataView(ds._data);
for (let offset = 0; offset < source.byteLength; offset++) {
definition.setUint8(offset, source.getUint8(offset));
}
return ds;
}
/**
* Warning!
*
* This ArrayBuffer will be detached as soon as its
* size is changed!
*/
get data() {
return this._data;
}
/** Get number of attributes. */
get count() {
return this._count;
}
/** Set number of attributes (reallocate data accordingly) */
set count(count) {
if (this._count === count)
return;
this._count = count;
this._data = resize(this._data, count * this.stride);
}
get attributesNames() {
return Object.keys(this.attributesDefinition);
}
getAttribAccessor(attribName) {
const definition = this.getDef(attribName);
const view = new DataView(this.data);
const stride = this.stride;
return {
get(index, dimension = 0) {
const byteOffset = definition.byteOffset +
stride * index +
dimension * definition.bytesPerElement;
return definition.getter(view, byteOffset);
},
set(value, index, dimension = 0) {
const byteOffset = definition.byteOffset +
stride * index +
dimension * definition.bytesPerElement;
definition.setter(view, byteOffset, value);
},
};
}
/**
* Set the data for one attribute.
*
* If you try to set more element that the current buffer
* can hold, the buffer will be expanded.
* And the property `count` will change accordingly.
*
* @param attribName If the attribute does not exist,
* you will get an exception.
* @param value The ArrayBuffer holding the data you
* want to set to this attribute
* @param param2
*/
set(attribName, value, { byteOffset = 0, byteStride, first = 0, count = Infinity, targetFirst = 0, } = {}) {
const { bytesPerElement, dimension, byteOffset: attribByteOffset, } = this.getDef(attribName);
const buffer = value instanceof ArrayBuffer ? value : value.buffer;
const chunkLength = bytesPerElement * dimension;
const sourceStride = byteStride !== null && byteStride !== void 0 ? byteStride : chunkLength;
let sourceOffset = byteOffset + sourceStride * first;
const dstStride = this.stride;
let dstOffset = targetFirst * dstStride + attribByteOffset;
this.count = Math.max(this.count, Math.min(count, Math.floor((buffer.byteLength - sourceOffset) / sourceStride)));
const sourceStop = buffer.byteLength - sourceStride + 1;
const dstStop = this._data.byteLength + attribByteOffset - dstStride + 1;
const sourceBuffer = new Uint8Array(buffer);
const dstBuffer = new Uint8Array(this._data);
let index = 0;
while (index < count &&
sourceOffset < sourceStop &&
dstOffset < dstStop) {
dstBuffer.set(sourceBuffer.subarray(sourceOffset, sourceOffset + chunkLength), dstOffset);
index++;
sourceOffset += sourceStride;
dstOffset += dstStride;
}
}
getDef(attribName) {
const definition = this.definitions[attribName];
if (!definition)
throw new Error(`[TgdDataset] Attribute "${String(attribName)}" not found in this DataSet!\nAvailable names are: ${Object.keys(this.definitions)
.map(name => JSON.stringify(name))
.join(", ")}.`);
return definition;
}
/**
* Enable the vertex attrib array, and set
* the vertex attrib pointer for every declared
* attribute.
*/
defineAttributes(gl, prg) {
let offsetDestination = 0;
const { definitions } = this;
for (const name of Object.keys(definitions)) {
const definition = definitions[name];
if (prg.hasAttribute(name)) {
const att = prg.getAttribLocation(name);
gl.enableVertexAttribArray(att);
gl.vertexAttribPointer(att, definition.dimension, gl.FLOAT, false, this.stride, offsetDestination);
gl.vertexAttribDivisor(att, definition.divisor);
}
const bytes = definition.dimension * definition.bytesPerElement;
offsetDestination += bytes;
}
}
toCode({ indent = "" } = {}) {
const lines = [];
let offsetDestination = 0;
const { definitions } = this;
for (const name of Object.keys(definitions)) {
const definition = definitions[name];
const att = `$${name}`;
lines.push(`const ${att} = gl.getAttribLocation(prg, "${name}")`, `gl.enableVertexAttribArray(${att})`, `gl.vertexAttribPointer(`, ` ${att},`, ` ${definition.dimension}, // Dimension`, ` gl.FLOAT,`, ` false,`, ` ${this.stride}, // Stride`, ` ${offsetDestination} // Offset`, `)`, `gl.vertexAttribDivisor(${att}, ${definition.divisor})`);
const bytes = definition.dimension * definition.bytesPerElement;
offsetDestination += bytes;
}
return lines.map(line => `${indent}${line}`).join("\n");
}
debug(caption = "Dataset") {
console.log(caption, " count:", this.count, " target:", this.target, " usage:", this.usage);
const rows = [
["Name", "type", "offset"],
];
for (const attName of Object.keys(this.definitions)) {
const definition = this.definitions[attName];
rows.push([
attName,
this.attributesDefinition[attName],
`${definition.byteOffset}`,
]);
}
const sizes = [0, 1, 2].map(index => rows.reduce((previous, current) => Math.max(previous, current[index].length), 0));
for (const [name, type, offset] of rows)
console.log(`%c${name.padEnd(sizes[0] + 2)}${type.padStart(sizes[1] + 2)}${offset.padStart(sizes[2] + 2)}`, "font-family:monospace");
for (const attName of Object.keys(this.definitions)) {
const definition = this.definitions[attName];
if (!definition)
continue;
const { get } = this.getAttribAccessor(attName);
const data = [];
for (let index = 0; index < this.count; index++) {
const items = [];
for (let dim = 0; dim < definition.dimension; dim++) {
items.push(get(index, dim));
}
data.push(items);
}
console.log(`Attribute "${attName}":`, data);
}
}
}
const DIMS = {
float: 1,
vec2: 2,
vec3: 3,
vec4: 4,
};
function resizeFast(buff, newSize) {
return buff.transfer(newSize);
}
function resizeSlow(inBuff, newSize) {
const outBuff = new ArrayBuffer(newSize !== null && newSize !== void 0 ? newSize : inBuff.byteLength);
new Uint8Array(outBuff).set(new Uint8Array(inBuff));
return outBuff;
}
const resize = typeof ArrayBuffer.prototype.transfer === "function"
? resizeFast
: resizeSlow;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhc2V0L2RhdGFzZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY0EsTUFBTSxPQUFPLFVBQVU7SUFTbkIsWUFDcUIsb0JBQTBDLEVBQzFDLFVBQXNDLEVBQUU7O1FBRHhDLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBc0I7UUFDMUMsWUFBTyxHQUFQLE9BQU8sQ0FBaUM7UUFWckQsV0FBTSxHQUFXLENBQUMsQ0FBQTtRQUNsQixnQkFBVyxHQUFvRCxFQUFFLENBQUE7UUFDakUsVUFBSyxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQzFCLFdBQU0sR0FBRyxDQUFDLENBQUE7UUFTZCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQUEsT0FBTyxDQUFDLE1BQU0sbUNBQUksY0FBYyxDQUFBO1FBQzlDLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBQSxPQUFPLENBQUMsS0FBSyxtQ0FBSSxhQUFhLENBQUE7UUFDM0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxvQkFBb0IsRUFBRSxPQUFPLENBQUMsQ0FBQTtJQUNsRCxDQUFDO0lBRU8sVUFBVSxDQUNkLG9CQUEwQyxFQUMxQyxVQUFzQyxFQUFFOztRQUV4QyxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDO1lBQ25ELE1BQU0sVUFBVSxHQUFHLG9CQUFvQixDQUFDLElBQUksQ0FBQyxDQUFBO1lBQzdDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsR0FBRyxVQUFVLENBQUE7UUFDaEQsQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLE1BQUEsT0FBTyxDQUFDLE9BQU8sbUNBQUksQ0FBQyxDQUFBO1FBQ3BDLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQTtRQUNkLE1BQU0sSUFBSSxHQUFtQyxFQUFFLENBQUE7UUFDL0MsTUFBTSxXQUFXLEdB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