@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
239 lines • 19.3 kB
JavaScript
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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