This commit is contained in:
@@ -179,6 +179,24 @@ function makeMaterial(color: [number, number, number] | null): THREE.MeshStandar
|
||||
})
|
||||
}
|
||||
|
||||
// ---- Binary decode helpers (geometry v2) ---------------------------------
|
||||
|
||||
function b64ToFloat32(b64: string): Float32Array {
|
||||
const bin = atob(b64)
|
||||
const buf = new ArrayBuffer(bin.length)
|
||||
const u8 = new Uint8Array(buf)
|
||||
for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i)
|
||||
return new Float32Array(buf)
|
||||
}
|
||||
|
||||
function b64ToUint32(b64: string): Uint32Array {
|
||||
const bin = atob(b64)
|
||||
const buf = new ArrayBuffer(bin.length)
|
||||
const u8 = new Uint8Array(buf)
|
||||
for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i)
|
||||
return new Uint32Array(buf)
|
||||
}
|
||||
|
||||
// ---- STEP/STP loader (geometry JSON, pre-processed server-side) ----------
|
||||
|
||||
async function loadStepGeometry(): Promise<void> {
|
||||
@@ -193,28 +211,64 @@ async function loadStepGeometry(): Promise<void> {
|
||||
throw new Error(`Could not load geometry (HTTP ${res.status})`)
|
||||
}
|
||||
|
||||
setLoading('Building 3D scene…')
|
||||
const data = await res.json() as GeometryFile
|
||||
// Stream the response body so there is visible activity during large downloads
|
||||
let text: string
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader()
|
||||
const chunks: Uint8Array[] = []
|
||||
let loaded = 0
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
chunks.push(value)
|
||||
loaded += value.byteLength
|
||||
setLoading(`Downloading geometry… ${Math.round(loaded / 1024)} KB`)
|
||||
}
|
||||
setLoading('Parsing geometry…')
|
||||
text = new TextDecoder().decode(
|
||||
chunks.reduce((acc, c) => { const m = new Uint8Array(acc.length + c.length); m.set(acc); m.set(c, acc.length); return m }, new Uint8Array(0))
|
||||
)
|
||||
} else {
|
||||
text = await res.text()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = JSON.parse(text) as GeometryFile & { version: number; meshes: any[] }
|
||||
|
||||
if (!data.meshes || data.meshes.length === 0) {
|
||||
throw new Error('Geometry file contains no meshes.')
|
||||
}
|
||||
|
||||
setLoading('Building 3D scene…')
|
||||
const group = new THREE.Group()
|
||||
const isV2 = data.version >= 2
|
||||
|
||||
for (const mesh of data.meshes) {
|
||||
const geo = new THREE.BufferGeometry()
|
||||
geo.setAttribute('position', new THREE.Float32BufferAttribute(mesh.positions, 3))
|
||||
|
||||
if (mesh.normals && mesh.normals.length > 0) {
|
||||
geo.setAttribute('normal', new THREE.Float32BufferAttribute(mesh.normals, 3))
|
||||
let positions: Float32Array
|
||||
let normals: Float32Array | null
|
||||
let indices: Uint32Array | null
|
||||
|
||||
if (isV2) {
|
||||
positions = b64ToFloat32(mesh.positions)
|
||||
normals = mesh.normals ? b64ToFloat32(mesh.normals) : null
|
||||
indices = mesh.indices ? b64ToUint32(mesh.indices) : null
|
||||
} else {
|
||||
// Legacy v1: plain number arrays
|
||||
positions = new Float32Array(mesh.positions as number[])
|
||||
normals = mesh.normals ? new Float32Array(mesh.normals as number[]) : null
|
||||
indices = mesh.indices ? new Uint32Array(mesh.indices as number[]) : null
|
||||
}
|
||||
|
||||
if (mesh.indices && mesh.indices.length > 0) {
|
||||
geo.setIndex(new THREE.Uint32BufferAttribute(mesh.indices, 1))
|
||||
geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
|
||||
if (normals && normals.length > 0) {
|
||||
geo.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
|
||||
}
|
||||
|
||||
if (!mesh.normals || mesh.normals.length === 0) {
|
||||
if (indices && indices.length > 0) {
|
||||
geo.setIndex(new THREE.Uint32BufferAttribute(indices, 1))
|
||||
}
|
||||
if (!normals || normals.length === 0) {
|
||||
geo.computeVertexNormals()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user