wmc/skycraft/obj.js
Paul Mathieu 7354dcb929 skycraft: sexier spaceship
now with wavefront .obj format support
2022-11-09 00:44:48 -08:00

72 lines
2.1 KiB
JavaScript

function parseObjLine(line, obj) {
line = line.trim();
if (line[0] === '#' || line.length < 1) {
return;
}
const elements = line.split(/\s+/);
obj[elements[0]].push(elements.slice(1));
}
function getFaces(obj) {
return obj.f.map(f => {
const face = {
'vertices': [],
'normals': [],
'textures': [],
};
if (f.length === 4) { // add duplicate vertices to make triangles
f.splice(3, 0, f[0]);
f.splice(4, 0, f[2]);
}
f.forEach(v => {
const [vidx, vtidx, vnidx] = v.split('/');
face.vertices.push((obj.v[vidx - 1] || []).map(Number));
face.normals.push((obj.vn[vnidx - 1] || []).map(Number));
//face.textures.push((obj.vt[vtidx] || []).map(Number));
face.textures.push([0, 0]);
});
return face;
});
}
export async function loadObjModel(url) {
const stlDataStream = (await fetch(url)).body;
const faces = [];
const obj = new Proxy({}, {
get: (target, name) =>{
if (!(name in target)) {
target[name] = [];
}
return target[name];
},
});
return new Promise((resolve, reject) => {
let partialLine = "";
const reader = stlDataStream.getReader();
const decoder = new TextDecoder();
function pump() {
reader.read().then(({ done, value }) => {
if (done) {
parseObjLine(partialLine, obj);
return resolve(getFaces(obj));
}
const textInput = decoder.decode(value);
const lines = textInput.split('\n');
if (lines.length > 1) {
parseObjLine(partialLine + lines[0], obj);
partialLine = "";
lines.slice(0, -1).forEach(line => {
parseObjLine(line, obj);
});
}
partialLine = partialLine + lines.at(-1);
pump();
});
}
pump();
});
}