UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

274 lines 26 kB
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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