UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

167 lines 15.4 kB
import { TgdDataset } from "./../dataset/index.js"; import { isTgdTypeArrayForElements } from "./../types/index.js"; import { TgdVec3 } from "./../math/index.js"; import { webglElementTypeFromTypedArray, webglLookup } from "./../utils/index.js"; import { TgdBoundingBox, tgdGeometryJoin } from "../index.js"; /** * Geometry is used to define a mesh. * It must hold at least one vec3 attributes * for the vertices. */ export class TgdGeometry { static make(options) { const definition = {}; const { count, drawMode, elements, attPosition, attNormal, attUV, computeNormalsIfMissing } = options; definition[attPosition.name] = attPosition.type ?? "vec3"; if (attNormal) definition[attNormal.name] = attNormal.type ?? "vec3"; if (attUV) definition[attUV.name] = attUV.type ?? "vec2"; const dataset = new TgdDataset(definition); dataset.set(attPosition.name, attPosition.data); if (attNormal) dataset.set(attNormal.name, attNormal.data); if (attUV) dataset.set(attUV.name, attUV.data); return new TgdGeometry({ dataset, count, drawMode, elements, computeNormalsIfMissing, }); } static fitElementsInTypeArray(elements) { if (isTgdTypeArrayForElements(elements)) return elements; const max = elements.reduce((prv, cur) => Math.max(prv, cur), 0); if (max <= 0xff) return new Uint8Array(elements); if (max <= 0xffff) return new Uint16Array(elements); return new Uint32Array(elements); } static join(geometries) { return tgdGeometryJoin(geometries); } constructor(options) { const { dataset, drawMode = "TRIANGLES", attPosition = "POSITION", attNormal = "NORMAL", attUV = "TEXCOORD_0", name = `TgdGeometry#${TgdGeometry.counter++}`, } = options; this.name = name; this._dataset = dataset; this.drawMode = typeof drawMode === "number" ? drawMode : WebGL2RenderingContext[drawMode]; const { elements } = options; this.elements = elements; this._elementsType = elements ? webglElementTypeFromTypedArray(elements) : 0; this.attPosition = attPosition; this.attNormal = attNormal; this.attUV = attUV; this.count = elements?.length ?? dataset.count; if (options.computeNormalsIfMissing) this.computeNormals(); } debug(caption) { const label = `[${caption ?? this.name}]`; this.dataset.debug(`${label} Dataset`); console.debug(`${label} Count:`, this.count); console.debug(`${label} DrawMode:`, webglLookup(this.drawMode)); console.debug(this.computeBoundingBox()); } get dataset() { return this._dataset; } get elementsType() { return this._elementsType; } /** * Return the index of a vertex. * If no elements array has been defined, we return `index` verbatim. * Otherwise, we use this elements array. */ getElement(index) { return this.elements?.[index] ?? index; } computeNormals() { let normals = []; if (this.drawMode === WebGL2RenderingContext.TRIANGLES) { normals = this.computeNormalsForTrianglesDrawMode(); } else { console.error("We don't know how to compute normals for this draw mode:", this.drawMode); return this; } const attNormalName = this.attNormal; this.dataset.addAttributes({ [attNormalName]: "vec3", }); const values = []; for (const [nx, ny, nz] of normals) { values.push(nx, ny, nz); } this.dataset.set(attNormalName, new Float32Array(values)); return this; } computeBoundingBox() { const bbox = new TgdBoundingBox(); const { get } = this.dataset.getAttribAccessor(this.attPosition); for (let index = 0; index < this.count; index++) { const x = get(index, 0); const y = get(index, 1); const z = get(index, 2); bbox.addPoint(x, y, z); } return bbox; } computeNormalsForTrianglesDrawMode() { const ds = this.dataset; const normalsAccumulator = new Map(); const addNormal = (index, A, B, C) => { const norm = computeNormal(A, B, C); const item = normalsAccumulator.get(index); if (item) { item.add(norm); } else { normalsAccumulator.set(index, new TgdVec3(norm.x, norm.y, norm.z)); } }; const { get } = ds.getAttribAccessor(this.attPosition); const indexes = new Set(); let indexMax = 0; for (let element = 0; element < this.count; element += 3) { const index0 = this.getElement(element + 0); indexes.add(index0); indexMax = Math.max(indexMax, index0); const index1 = this.getElement(element + 1); indexes.add(index1); indexMax = Math.max(indexMax, index1); const index2 = this.getElement(element + 2); indexes.add(index2); indexMax = Math.max(indexMax, index2); const A = new TgdVec3(get(index0, 0), get(index0, 1), get(index0, 2)); const B = new TgdVec3(get(index1, 0), get(index1, 1), get(index1, 2)); const C = new TgdVec3(get(index2, 0), get(index2, 1), get(index2, 2)); addNormal(index0, A, B, C); addNormal(index1, B, C, A); addNormal(index2, C, A, B); } const normals = []; for (let index = 0; index <= indexMax; index++) { const item = normalsAccumulator.get(index); if (item) { item.normalize(); normals.push(item); } else { normals.push(new TgdVec3()); } } return normals; } } TgdGeometry.counter = 1; function computeNormal(A, B, C) { const AB = new TgdVec3(B).subtract(A); const AC = new TgdVec3(C).subtract(A); return AB.cross(AC).normalize(); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VvbWV0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZ2VvbWV0cnkvZ2VvbWV0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBd0MsTUFBTSxjQUFjLENBQUE7QUFDL0UsT0FBTyxFQUFFLHlCQUF5QixFQUEwQyxNQUFNLFlBQVksQ0FBQTtBQUM5RixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ25DLE9BQU8sRUFBRSw4QkFBOEIsRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDeEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxlQUFlLEVBQUUsTUFBTSxJQUFJLENBQUE7QUF3Q3BEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sV0FBVztJQWlCYixNQUFNLENBQUMsSUFBSSxDQUFDLE9BQTRCO1FBQzNDLE1BQU0sVUFBVSxHQUF5QixFQUFFLENBQUE7UUFDM0MsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLHVCQUF1QixFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQ3JHLFVBQVUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsV0FBVyxDQUFDLElBQUksSUFBSSxNQUFNLENBQUE7UUFDekQsSUFBSSxTQUFTO1lBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQTtRQUNwRSxJQUFJLEtBQUs7WUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFBO1FBQ3hELE1BQU0sT0FBTyxHQUFHLElBQUksVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMs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