UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

241 lines 19.4 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; var _b; 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 = (_b = this.trianglesPerVertex)[vertexIndex]) !== null && _a !== void 0 ? _a : (_b[vertexIndex] = []); this.trianglesPerVertex[vertexIndex].push(triangleIndex); } }; /** * Return the index of the vertex for the triplet * point/normal/uv. */ this.getElem = (triangleSummit) => { var _a; const k = this.key(triangleSummit); const index = (_a = this.mapVertices.get(k)) !== null && _a !== void 0 ? _a : -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F2ZWZyb250LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3BhcnNlci9tZXNoL3dhdmVmcm9udC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUNuQyxPQUFPLEVBQUUsV0FBVyxFQUF1QixNQUFNLGVBQWUsQ0FBQTtBQVFoRTs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLE9BQU8sc0JBQXNCO0lBK0MvQixZQUFZLE9BQWU7UUE5Q25CLFNBQUksR0FBRyxNQUFNLENBQUE7UUFDYixnQkFBVyxHQUFhLEVBQUUsQ0FBQTtRQUMxQixjQUFTLEdBQWEsRUFBRSxDQUFBO1FBQ3hCLFVBQUssR0FBYSxFQUFFLENBQUE7UUFDNUI7OztXQUdHO1FBQ0ssYUFBUSxHQUFhLEVBQUUsQ0FBQTtRQUV2QixpQkFBWSxHQUFHLENBQUMsQ0FBQTtRQUN4Qjs7O1dBR0c7UUFDYyxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFBO1FBQ3hEOzs7OztXQUtHO1FBQ0ssV0FBTSxHQUErQixFQUFFLENBQUE7UUFDL0M7O1dBRUc7UUFDSyxZQUFPLEdBQStCLEVBQUUsQ0FBQTtRQUNoRDs7O1dBR0c7UUFDSyx3QkFBbUIsR0FBZSxFQUFFLENBQUE7UUFDNUM7O1dBRUc7UUFDSyxzQkFBaUIsR0FBYyxFQUFFLENBQUE7UUFDekM7OztXQUdHO1FBQ0ssdUJBQWtCLEdBQWUsRUFBRSxDQUFBO1FBQzNDOztXQUVHO1FBQ0ssUUFBRyxHQUFlLEVBQUUsQ0FBQTtRQXdGWCxhQUFRLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRTtZQUN6QyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQTtRQUNwQixDQUFDLENBQUE7UUFFZ0IsYUFBUSxHQUFHLENBQUMsQ0FBUyxFQUFFLENBQVMsRUFB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