UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

239 lines 19.3 kB
import { forEachLine } from "../for-each-line.js"; import { TgdVec3 } from "./../../math/index.js"; import { TgdGeometry } from "./../../geometry/index.js"; /** * This [Wavefront](https://en.wikipedia.org/wiki/Wavefront_.obj_file) * parser only finds the object name, * the vertices coords, the normals and the UVs. * * - There can be only one object per file. * - Normals and UVs are optional. * - All faces **must** be triangles. * * To export an obj file from blender, please use the following options: * * - Forward axis: **Y** * - Up axis: **Z** * - Object / Apply Modifiers: **True** * - Geometry / UV Coordinates: **True** * - Geometry / Normals: **True** * - Geometry / Triangulated Mesh: **True** */ export class TgdParserMeshWavefront { constructor(content) { this.name = "Mesh"; this.attPosition = []; this.attNormal = []; this.attUV = []; /** * Three consecutive elements define a triangle. * An element is a index on the attributes array. */ this.elements = []; this.elementIndex = 0; /** * The key is `${pointIndex}/${normalIndex}/${uvIndex}`. * The value is the index of the vertex (used in `elements`). */ this.mapVertices = new Map(); /** * A point ins not a vertex, but just a position in space * that can be used by several different vertices. * That's the case for faces sharing a vertex but having different * normals. A vertex is made of a position, a normal and an uv. */ this.points = []; /** * A item of this array can be shared by different vertices. */ this.normals = []; /** * List of vertices per face. * The vertices are represented by the index of the attribute. */ this.verticesPerTriangle = []; /** * Here "normal" is an index on `this.normals` array. */ this.normalPerTriangle = []; /** * The vertices are indexed per attribute. * The triangles are represented by indexes from `this.normalPerTriangle`. */ this.trianglesPerVertex = []; /** * A item of this array can be shared by different vertices. */ this.uvs = []; this.onObject = (name) => { this.name = name; }; this.onVertex = (x, y, z) => { this.points.push([x, y, z]); }; this.onNormal = (x, y, z) => { this.normals.push([x, y, z]); }; this.onTexture = (u, v) => { this.uvs.push([u, v]); }; this.onFace = (vertices) => { var _a; if (vertices.length !== 3) throw new Error("We can only deal with triangles!"); const triangle = vertices.map((vertex) => this.getElem(vertex)); this.elements.push(...triangle); this.normalPerTriangle.push(new TgdVec3(0, 0, 0)); this.verticesPerTriangle.push(triangle); const triangleIndex = this.normalPerTriangle.length - 1; for (const vertexIndex of triangle) { (_a = this.trianglesPerVertex)[vertexIndex] ?? (_a[vertexIndex] = []); this.trianglesPerVertex[vertexIndex].push(triangleIndex); } }; /** * Return the index of the vertex for the triplet * point/normal/uv. */ this.getElem = (triangleSummit) => { const k = this.key(triangleSummit); const index = this.mapVertices.get(k) ?? -1; if (index > -1) return index; const [vx, vy, vz] = this.points[triangleSummit.vertex]; this.attPosition.push(vx, vy, vz); if (typeof triangleSummit.normal === "number") { const [nx, ny, nz] = this.normals[triangleSummit.normal]; this.attNormal.push(nx, ny, nz); } if (typeof triangleSummit.uv === "number") { const [tx, ty] = this.uvs[triangleSummit.uv]; this.attUV.push(tx, ty); } this.mapVertices.set(k, this.elementIndex); return this.elementIndex++; }; this.reset(); const { onVertex, onNormal, onTexture, onFace, onObject } = this; parse(content, { onVertex, onNormal, onTexture, onFace, onObject }); } makeGeometry({ computeNormals } = {}) { const options = { attPosition: { name: "POSITION", data: new Float32Array(this.attPosition), }, computeNormalsIfMissing: computeNormals, }; if (this.attNormal.length > 0) { options.attNormal = { name: "NORMAL", data: new Float32Array(this.attNormal), }; } if (this.attUV.length > 0) { options.attUV = { name: "TEXTCOORDS_0", data: new Float32Array(this.attUV), }; } const { elements, elementIndex } = this; if (elementIndex <= 256) { options.elements = new Uint8Array(elements); } else if (elementIndex <= 0x10000) { options.elements = new Uint16Array(elements); } else { options.elements = new Uint32Array(elements); } return TgdGeometry.make(options); } computeNormals() { const A = new TgdVec3(); const B = new TgdVec3(); const C = new TgdVec3(); for (const [triangleIndex, normal] of this.normalPerTriangle.entries()) { const [v0, v1, v2] = this.verticesPerTriangle[triangleIndex]; this.readVertexInto(v0, A); this.readVertexInto(v1, B).subtract(A); this.readVertexInto(v2, C).subtract(A); normal.from(B.cross(C).normalize()); } this.attNormal = []; for (let elementIndex = 0; elementIndex < this.elementIndex; elementIndex++) { const normal = new TgdVec3(0, 0, 0); for (const triIndex of this.trianglesPerVertex[elementIndex]) normal.add(this.normalPerTriangle[triIndex]); const [nx, ny, nz] = normal.normalize(); this.attNormal.push(nx, ny, nz); } } reset() { this.name = "Mesh"; this.attPosition = []; this.attNormal = []; this.attUV = []; this.elements = []; this.elementIndex = 0; this.points = []; this.normals = []; this.verticesPerTriangle = []; this.trianglesPerVertex = []; this.normalPerTriangle = []; this.uvs = []; this.mapVertices.clear(); this.mapVertices.clear(); } key(v) { return `${v.vertex}/${v.normal}`; } readVertexInto(index, target) { const P = this.attPosition; const k = index * 3; target.reset(P[k + 0], P[k + 1], P[k + 2]); return target; } } function parse(content, options = {}) { const { onVertex, onNormal, onTexture, onFace, onObject } = options; for (const fullLine of forEachLine(content)) { const line = fullLine.trimStart(); if (onVertex && line.startsWith("v ")) { const vertex = line.slice("v ".length).split(" ").map(Number); if (isVector3(vertex)) onVertex(...vertex); } else if (onFace && line.startsWith("f ")) { onFace(line .slice("f ".length) .split(" ") // Warning! We need to remove 1 to the index. .map((face) => { const [v, t, n] = face.split("/"); return { vertex: Number(v) - 1, normal: n ? Number(n) - 1 : undefined, uv: t ? Number(t) - 1 : undefined, }; })); } else if (onNormal && line.startsWith("vn ")) { const normal = line.slice("vn ".length).split(" ").map(Number); if (isVector3(normal)) onNormal(...normal); } else if (onTexture && line.startsWith("vt ")) { const [u, v, w] = line.slice("vt ".length).split(" ").map(Number); onTexture(u, v, w); } else if (onObject && line.startsWith("o ")) { const name = line.slice("o ".length); onObject(name); } } } function isVector3(data) { return data.length === 3; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F2ZWZyb250LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3BhcnNlci9tZXNoL3dhdmVmcm9udC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUNuQyxPQUFPLEVBQUUsV0FBVyxFQUF1QixNQUFNLGVBQWUsQ0FBQTtBQVFoRTs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLE9BQU8sc0JBQXNCO0lBK0MvQixZQUFZLE9BQWU7UUE5Q25CLFNBQUksR0FBRyxNQUFNLENBQUE7UUFDYixnQkFBVyxHQUFhLEVBQUUsQ0FBQTtRQUMxQixjQUFTLEdBQWEsRUFBRSxDQUFBO1FBQ3hCLFVBQUssR0FBYSxFQUFFLENBQUE7UUFDNUI7OztXQUdHO1FBQ0ssYUFBUSxHQUFhLEVBQUUsQ0FBQTtRQUV2QixpQkFBWSxHQUFHLENBQUMsQ0FBQTtRQUN4Qjs7O1dBR0c7UUFDYyxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFBO1FBQ3hEOzs7OztXQUtHO1FBQ0ssV0FBTSxHQUErQixFQUFFLENBQUE7UUFDL0M7O1dBRUc7UUFDSyxZQUFPLEdBQStCLEVBQUUsQ0FBQTtRQUNoRDs7O1dBR0c7UUFDSyx3QkFBbUIsR0FBZSxFQUFFLENBQUE7UUFDNUM7O1dBRUc7UUFDSyxzQkFBaUIsR0FBYyxFQUFFLENBQUE7UUFDekM7OztXQUdHO1FBQ0ssdUJBQWtCLEdBQWUsRUFBRSxDQUFBO1FBQzNDOztXQUVHO1FBQ0ssUUFBRyxHQUFlLEVBQUUsQ0FBQTtRQThFWCxhQUFRLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRTtZQUN6QyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQTtRQUNwQixDQUFDLENBQUE7UUFFZ0IsYUFBUSxHQUFHLENBQUMsQ0FBUyxFQUFFLENBQVMsRUFB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