wmc/skycraft/stl.js
Paul Mathieu 216ef470c5 skycraft: orbit computatino still borken
But we got ourselves a spaceship!
Improved the camera a bit. Now we can see the ship's orbit.
2022-11-08 00:33:51 -08:00

76 lines
2.5 KiB
JavaScript

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();
});
}