function _parseBin(i){const o=new DataView(i).getUint32(0,!0),a=JSON.parse(new TextDecoder().decode(new Uint8Array(i,4,o))),n=4+o,s={};for(const e of a.sections){const t=i.slice(n+e.offset,n+e.offset+e.length),f=e.dtype==="uint8"?new Uint8Array(t):e.dtype==="uint16"?new Uint16Array(t):e.dtype==="float16"?new Uint16Array(t):e.dtype==="float32"?new Float32Array(t):new Uint8Array(t);s[e.name]={...e,view:f}}return{meta:a,sections:s}}function _tex3D(i,r,o,a=THREE.LinearFilter){const[n,s,e]=i.shape,t=new THREE.Data3DTexture(i.view,n,s,e);return t.format=r,t.type=o,t.minFilter=t.magFilter=a,t.wrapS=t.wrapT=t.wrapR=THREE.ClampToEdgeWrapping,t.unpackAlignment=1,t.needsUpdate=!0,t}function _spawnTexture(i,r,o){const a=Math.max(1,i.shape[0]),n=new Float32Array(a*4),s=i.view;for(let t=0;t<a;t++)n[4*t]=r[0]+(s[3*t]+.5)*o,n[4*t+1]=r[1]+(s[3*t+1]+.5)*o,n[4*t+2]=r[2]+(s[3*t+2]+.5)*o,n[4*t+3]=1;const e=new THREE.DataTexture(n,a,1,THREE.RGBAFormat,THREE.FloatType);return e.minFilter=e.magFilter=THREE.NearestFilter,e.needsUpdate=!0,{tex:e,n:a}}function _sampleInside(i,r,o,a){const[n,s,e]=i.shape,t=i.view,f=[];for(let l=0;l<t.length;l++)t[l]&&f.push(l);const d=new Float32Array(a*4);for(let l=0;l<a;l++){const w=f[Math.floor(Math.random()*f.length)],T=w%n,y=Math.floor(w/n)%s,E=Math.floor(w/(n*s));d[4*l]=r[0]+(T+Math.random())*o,d[4*l+1]=r[1]+(y+Math.random())*o,d[4*l+2]=r[2]+(E+Math.random())*o,d[4*l+3]=0}return{positions:d,insideCount:f.length}}async function loadRegion(i,r,o){const a=await fetch(`${i}/${r}.bin`);if(!a.ok)throw new Error(`\u6D41\u573A ${r}.bin\uFF1AHTTP ${a.status}`);const{meta:n,sections:s}=_parseBin(await a.arrayBuffer()),e=n.h,t=n.origin,f=n.dims,d={};for(const c of Object.keys(s))/^(flow|fill|eject)(@|$)/.test(c)&&(d[c]=_tex3D(s[c],THREE.RGBAFormat,THREE.UnsignedByteType));const l=_tex3D(s.dist,THREE.RedFormat,THREE.UnsignedByteType),w=_tex3D(s.inside,THREE.RedFormat,THREE.UnsignedByteType,THREE.NearestFilter),T={};for(const c of n.deform.keys){const p=s["deform_"+c];p&&(T[c]=_tex3D(p,THREE.RGBAFormat,THREE.HalfFloatType))}const y={},E={};for(const c of Object.keys(s))/^inlet_voxels(@|$)/.test(c)&&(y[c.slice(13)||"base"]=_spawnTexture(s[c],t,e)),/^outlet_voxels(@|$)/.test(c)&&(E[c.slice(14)||"base"]=_spawnTexture(s[c],t,e));return o&&o(r),{name:r,meta:n,h:e,origin:t,dims:f,size:f.map(c=>c*e),flowTex:d,dist:l,inside:w,insideSection:s.inside,deform:T,inlet:y.base,outlet:E.base,inlets:y,outlets:E}}async function loadFlowData(i="assets/flow",r){const o=await fetch(`${i}/manifest.json`);if(!o.ok)throw new Error(`\u6D41\u573A manifest\uFF1AHTTP ${o.status}`);const a=await o.json(),n={},s=Object.keys(a.regions);return await Promise.all(s.map(async e=>{n[e]=await loadRegion(i,e,r)})),{manifest:a,regions:n}}Object.assign(window,{loadFlowData,loadRegion,_sampleInside});
