import assert from 'node:assert/strict' import {instanceSafePrimitives,decodePrimitive,rotate,safeNormalDot} from './instance-safe-primitives.mjs' import {packGlb,parseGlb,accessorValues} from './instance-repeated-meshes.mjs' import {compressInstanceBuffers,unpackInstanceBuffers} from './instance-buffer-codec.mjs' const bin=Buffer.alloc(84),positions=[-1,-1,0,1,-1,0,-1,1,0],normals=[0,0,1,0,0,1,0,0,1] positions.concat(normals).forEach((v,i)=>bin.writeFloatLE(v,i*4));[0,1,2].forEach((v,i)=>bin.writeUInt32LE(v,72+i*4)) const json={asset:{version:'2.0'},scene:0,scenes:[{nodes:[0,1]}],nodes:[{name:'a',mesh:0,translation:[2,3,4],scale:[20,4,3],rotation:[0,0.6,0,0.8]}, {name:'b',mesh:0,translation:[7,8,9],scale:[10,2,7]}],meshes:[{primitives:[{attributes:{POSITION:0,NORMAL:1},indices:2,material:0}]}],materials:[{name:'wall'}],buffers:[{byteLength:84}], bufferViews:[{buffer:0,byteOffset:0,byteLength:36},{buffer:0,byteOffset:36,byteLength:36},{buffer:0,byteOffset:72,byteLength:12}], accessors:[{bufferView:0,componentType:5126,count:3,type:'VEC3'},{bufferView:1,componentType:5126,count:3,type:'VEC3'},{bufferView:2,componentType:5125,count:3,type:'SCALAR'}]} const result=instanceSafePrimitives(packGlb(json,bin));assert.equal(result.report.instanceGroups,1);assert.equal(result.report.outputPrimitives,1) const compressed=compressInstanceBuffers(result.bytes),out=unpackInstanceBuffers(compressed),node=out.json.nodes[0],p=out.json.meshes[0].primitives[0],g=decodePrimitive(out.json,out.bin,p) assert.deepEqual(g.positions.slice(0,9),positions);assert.deepEqual(g.normals.slice(0,9),normals);assert.deepEqual(g.indices,[0,1,2]);assert.ok(Math.max(...g.indices)v+Math.min(...ts.map(t=>t[k]))),max=a.max.map((v,k)=>v+Math.max(...ts.map(t=>t[k]))),center=min.map((v,k)=>(v+max[k])/2),radius=Math.hypot(...min.map((v,k)=>(max[k]-v)/2)) for(let i=0;iv*ss[i][k]),rs[i]).map((v,k)=>v+ts[i][k]);assert.ok(Math.hypot(...q.map((v,k)=>v-center[k]))<=radius)} const sloped=Buffer.from(bin),n=[Math.SQRT1_2,Math.SQRT1_2,0];for(let i=0;i<3;i++)n.forEach((v,j)=>sloped.writeFloatLE(v,36+(i*3+j)*4)) assert.ok(safeNormalDot(n,[1.3,1,.7])<0.999999) assert.equal(instanceSafePrimitives(packGlb(json,sloped)).report.instanceGroups,0,'sloped normals must retain ordinary transforms') const mutated=structuredClone(json);mutated.meshes[0].primitives[0].targets=[{POSITION:0}];assert.throws(()=>instanceSafePrimitives(packGlb(mutated,bin))) const raw=parseGlb(result.bytes);assert.deepEqual(out.bin,raw.bin,'meshopt compression must be bit-lossless') console.log(JSON.stringify({passed:true,scope:'safe normal invariance, exact TRS, conservative command bounds, unused vertices, lossless meshopt, slope/morph rejection'}))