76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
import * as linalg from './linalg';
|
|
|
|
function parseTriangle(triangleData) {
|
|
const dv = new DataView(triangleData.buffer);
|
|
function data(idx) {
|
|
const offset = 4 * idx;
|
|
return dv.getFloat32(offset, /*littleEndian=*/true);
|
|
}
|
|
|
|
const attributeByteCount = dv.getUint16(48, /*littleEndian=*/true);
|
|
console.assert(attributeByteCount === 0);
|
|
|
|
const x = [data(3), data(4), data(5)];
|
|
const y = [data(6), data(7), data(8)];
|
|
const z = [data(9), data(10), data(11)];
|
|
const n = linalg.cross(linalg.diff(y, x), linalg.diff(z, y));
|
|
|
|
return {
|
|
vertices: [x, y, z],
|
|
normals: new Array(3).fill(linalg.scale(n, 1 / linalg.norm(n))),
|
|
textures: new Array(3).fill([0, 0]),
|
|
}; // no normals, default texture
|
|
}
|
|
|
|
export async function loadStlModel(url) {
|
|
const stlDataStream = (await fetch(url)).body;
|
|
const triangles = [];
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let bytesReceived = 0;
|
|
let gotHeader = false;
|
|
const partial = new Uint8Array(50); // each triangle is 50 bytes
|
|
let partialOffset = 0;
|
|
const reader = stlDataStream.getReader();
|
|
|
|
function pump() {
|
|
reader.read().then(({ done, value }) => {
|
|
if (done) {
|
|
return resolve(triangles);
|
|
}
|
|
|
|
const skipped = bytesReceived;
|
|
bytesReceived += value.length;
|
|
let inputOffset = 0;
|
|
|
|
if (!gotHeader) {
|
|
if (bytesReceived < 84) { // header + triangle count
|
|
return pump();
|
|
} else {
|
|
gotHeader = true;
|
|
inputOffset = 84 - skipped;
|
|
}
|
|
}
|
|
|
|
// parse triangle data
|
|
while (true) {
|
|
const spaceLeft = 50 - partialOffset;
|
|
console.assert(spaceLeft > 0);
|
|
|
|
const leftToCopy = value.length - inputOffset;
|
|
const toCopy = value.subarray(inputOffset, inputOffset + Math.min(leftToCopy, spaceLeft));
|
|
partial.set(toCopy, partialOffset);
|
|
if (leftToCopy < spaceLeft) {
|
|
break;
|
|
}
|
|
// parse a triangle!
|
|
triangles.push(parseTriangle(partial));
|
|
partialOffset = 0;
|
|
inputOffset += toCopy.length;
|
|
}
|
|
pump();
|
|
});
|
|
}
|
|
pump();
|
|
});
|
|
} |