first pass

This commit is contained in:
2026-07-03 22:04:34 -04:00
parent 2b1dd273b4
commit 2fa76da8bc
10973 changed files with 128242 additions and 0 deletions

97
geometry.js Normal file
View File

@@ -0,0 +1,97 @@
// geometry.js
const FACES = {
down: { n: [0, -1, 0], c: [[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1]] },
up: { n: [0, 1, 0], c: [[0, 1, 1], [1, 1, 1], [1, 1, 0], [0, 1, 0]] },
north: { n: [0, 0, -1], c: [[1, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]] },
south: { n: [0, 0, 1], c: [[0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]] },
west: { n: [-1, 0, 0], c: [[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 0]] },
east: { n: [1, 0, 0], c: [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]] }
};
export function resolveTexture(model, ref) {
if (!ref) return null;
if (ref[0] !== '#') return ref;
let key = ref.slice(1);
let val = model.textures?.[key];
// Follow variable chain
while (typeof val === 'string' && val[0] === '#') {
key = val.slice(1);
val = model.textures?.[key];
}
// Handle modern object-style textures
if (val && typeof val === 'object' && val.sprite) {
val = val.sprite;
}
return val || null;
}
export function buildGeometry(model, atlas) {
const pos = [];
const norm = [];
const uv = [];
const tint = [];
const idx = [];
let vOffset = 0;
for (const el of model.elements || []) {
// Map 0-16 voxel scale to 0.0-1.0 world scale
const [fx, fy, fz] = el.from.map(x => x / 16);
const [tx, ty, tz] = el.to.map(x => x / 16);
const size = [tx - fx, ty - fy, tz - fz];
for (const [name, face] of Object.entries(el.faces || {})) {
const tmpl = FACES[name];
const texPath = resolveTexture(model, face.texture);
const a = texPath ? atlas.map.get(texPath) : null;
// Skip faces with missing textures in the atlas
if (!a) continue;
// Basic UV fallback if omitted: this is a placeholder.
// Real implementation needs mapping based on face direction and element bounds.
const u1 = (face.uv?.[0] ?? 0) / 16;
const v1 = (face.uv?.[1] ?? 0) / 16;
const u2 = (face.uv?.[2] ?? 16) / 16;
const v2 = (face.uv?.[3] ?? 16) / 16;
const au1 = a.u + u1 * a.du;
const au2 = a.u + u2 * a.du;
// WebGL wants V flipped natively compared to Three.js canvas
const av1 = a.v + v1 * a.dv;
const av2 = a.v + v2 * a.dv;
const tintable = face.tintindex !== undefined ? 1.0 : 0.0;
for (let i = 0; i < 4; i++) {
const [cx, cy, cz] = tmpl.c[i];
// TODO: Apply el.rotation matrix here later
pos.push(fx + cx * size[0], fy + cy * size[1], fz + cz * size[2]);
norm.push(...tmpl.n);
tint.push(tintable);
}
uv.push(au1, av1, au2, av1, au2, av2, au1, av2);
// Push 2 triangles per quad
idx.push(
vOffset, vOffset + 1, vOffset + 2,
vOffset, vOffset + 2, vOffset + 3
);
vOffset += 4;
}
}
return {
positions: new Float32Array(pos),
normals: new Float32Array(norm),
uvs: new Float32Array(uv),
tints: new Float32Array(tint),
indices: new Uint16Array(idx)
};
}