@gltf-transform/functions
Advanced tools
Comparing version 3.1.2 to 3.1.3
@@ -1,2 +0,2 @@ | ||
import{Primitive as e,PropertyType as t,Document as n,getBounds as r,Scene as o,PrimitiveTarget as s,MathUtils as i,BufferUtils as a,Root as c,AnimationChannel as l,Texture as g,TextureInfo as u,ExtensionProperty as f,ImageUtils as p,ComponentTypeToTypedArray as m,Material as d,TextureChannel as h,Node as A,Accessor as y,AnimationSampler as E,uuid as T}from"@gltf-transform/core";import{getPixels as S,savePixels as I}from"ndarray-pixels";import{KHRMeshQuantization as M,KHRDracoMeshCompression as w,EXTMeshGPUInstancing as b,EXTMeshoptCompression as N,KHRMaterialsIOR as R,KHRMaterialsSpecular as C,KHRMaterialsPBRSpecularGlossiness as O,EXTTextureWebP as v,EXTTextureAVIF as P,KHRMaterialsUnlit as $}from"@gltf-transform/extensions";import{read as x,KHR_DF_MODEL_ETC1S as z,KHR_DF_MODEL_UASTC as L}from"ktx-parse";import q from"ndarray";import{lanczos3 as _,lanczos2 as k}from"ndarray-lanczos";function G(){return(G=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}function F(e,t){return Object.defineProperty(t,"name",{value:e}),t}function B(e,t,n){return!!e&&e.stack.lastIndexOf(t)<e.stack.lastIndexOf(n)}async function U(e,t,n){if(!e)return null;const r=e.getImage();if(!r)return null;const o=await S(r,e.getMimeType());for(let e=0;e<o.shape[0];++e)for(let t=0;t<o.shape[1];++t)n(o,e,t);const s=await I(o,"image/png");return t.setImage(s).setMimeType("image/png")}function W(t){const n=t.getIndices(),r=t.getAttribute("POSITION");switch(t.getMode()){case e.Mode.POINTS:return r.getCount();case e.Mode.LINES:return n?n.getCount()/2:r.getCount()/2;case e.Mode.LINE_LOOP:return r.getCount();case e.Mode.LINE_STRIP:return r.getCount()-1;case e.Mode.TRIANGLES:return n?n.getCount()/3:r.getCount()/3;case e.Mode.TRIANGLE_STRIP:case e.Mode.TRIANGLE_FAN:return r.getCount()-2;default:throw new Error("Unexpected mode: "+t.getMode())}}class H{constructor(){this._map=new Map}get size(){return this._map.size}has(e){return this._map.has(e)}add(e,t){let n=this._map.get(e);return n||(n=new Set,this._map.set(e,n)),n.add(t),this}get(e){return this._map.get(e)||new Set}keys(){return this._map.keys()}}function j(e,t=2){if(0===e)return"0 Bytes";const n=t<0?0:t,r=Math.floor(Math.log(e)/Math.log(1e3));return parseFloat((e/Math.pow(1e3,r)).toFixed(n))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][r]}function D(e){return e.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function V(e,t){return`${D(e)} → ${D(t)} (${function(e,t,n=2){return(e>t?"–":"+")+(Math.abs(e-t)/e*100).toFixed(n)+"%"}(e,t)})`}function X(e){const t=[];for(const n of e.listAttributes())t.push(n);for(const n of e.listTargets())for(const e of n.listAttributes())t.push(e);return Array.from(new Set(t))}function K(e,t,n){e.swap(t,n);for(const r of e.listTargets())r.swap(t,n)}function J(e,t,n){const r=e.getElementSize(),o=e.getCount(),s=e.getArray(),i=s.slice(0,n*r);for(let e=0;e<o;e++)for(let n=0;n<r;n++)i[t[e]*r+n]=s[e*r+n];e.setArray(i)}function Z(e,t=e){const n=t<=65534?new Uint16Array(e):new Uint32Array(e);for(let e=0;e<n.length;e++)n[e]=e;return n}function Q(e){const t=n.fromGraph(e.getGraph()),r=e.getMaterial();return`${t.getRoot().listMaterials().indexOf(r)}|${e.getMode()}|${!!e.getIndices()}|${e.listSemantics().sort().map(t=>{const n=e.getAttribute(t);return`${t}:${n.getElementSize()}:${n.getComponentType()}`}).join("+")}|${e.listTargets().map(t=>t.listSemantics().sort().map(t=>{const n=e.getAttribute(t);return`${t}:${n.getElementSize()}:${n.getComponentType()}`}).join("+")).join("~")}`}const Y={pivot:"center"};function ee(e=Y){const t=G({},Y,e);return F("center",e=>{const n=e.getLogger(),o=e.getRoot(),s=o.listAnimations().length>0||o.listSkins().length>0;e.getRoot().listScenes().forEach((i,a)=>{let c;if(n.debug(`center: Scene ${a+1} / ${o.listScenes().length}.`),"string"==typeof t.pivot){const e=r(i);c=[(e.max[0]-e.min[0])/2+e.min[0],(e.max[1]-e.min[1])/2+e.min[1],(e.max[2]-e.min[2])/2+e.min[2]],"above"===t.pivot&&(c[1]=e.max[1]),"below"===t.pivot&&(c[1]=e.min[1])}else c=t.pivot;n.debug(`center: Pivot "${c.join(", ")}".`);const l=[-1*c[0],-1*c[1],-1*c[2]];if(s){n.debug("center: Model contains animation or skin. Adding a wrapper node.");const t=e.createNode("Pivot").setTranslation(l);i.listChildren().forEach(e=>t.addChild(e)),i.addChild(t)}else n.debug("center: Skipping wrapper, offsetting all root nodes."),i.listChildren().forEach(e=>{const t=e.getTranslation();e.setTranslation([t[0]+l[0],t[1]+l[1],t[2]+l[2]])})}),n.debug("center: Complete.")})}function te(e){const t=new Set;let n,r=e;for(;n=r.getParentNode();){if(t.has(n))throw new Error("Circular dependency in scene graph.");t.add(n),r=n}return r.listParents().filter(e=>e instanceof o)}function ne(e){const t=te(e),n=e.getParentNode();if(!n)return e;e.setMatrix(e.getWorldMatrix()),n.removeChild(e);for(const n of t)n.addChild(e);return e}var re="undefined"!=typeof Float32Array?Float32Array:Array;function oe(e,t){var n=t[0],r=t[1],o=t[2],s=t[3],i=t[4],a=t[5],c=t[6],l=t[7],g=t[8],u=t[9],f=t[10],p=t[11],m=t[12],d=t[13],h=t[14],A=t[15],y=n*a-r*i,E=n*c-o*i,T=n*l-s*i,S=r*c-o*a,I=r*l-s*a,M=o*l-s*c,w=g*d-u*m,b=g*h-f*m,N=g*A-p*m,R=u*h-f*d,C=u*A-p*d,O=f*A-p*h,v=y*O-E*C+T*R+S*N-I*b+M*w;return v?(e[0]=(a*O-c*C+l*R)*(v=1/v),e[1]=(o*C-r*O-s*R)*v,e[2]=(d*M-h*I+A*S)*v,e[3]=(f*I-u*M-p*S)*v,e[4]=(c*N-i*O-l*b)*v,e[5]=(n*O-o*N+s*b)*v,e[6]=(h*T-m*M-A*E)*v,e[7]=(g*M-f*T+p*E)*v,e[8]=(i*C-a*N+l*w)*v,e[9]=(r*N-n*C-s*w)*v,e[10]=(m*I-d*T+A*y)*v,e[11]=(u*T-g*I-p*y)*v,e[12]=(a*b-i*R-c*w)*v,e[13]=(n*R-r*b+o*w)*v,e[14]=(d*E-m*S-h*y)*v,e[15]=(g*S-u*E+f*y)*v,e):null}function se(e,t,n){var r=t[0],o=t[1],s=t[2],i=t[3],a=t[4],c=t[5],l=t[6],g=t[7],u=t[8],f=t[9],p=t[10],m=t[11],d=t[12],h=t[13],A=t[14],y=t[15],E=n[0],T=n[1],S=n[2],I=n[3];return e[0]=E*r+T*a+S*u+I*d,e[1]=E*o+T*c+S*f+I*h,e[2]=E*s+T*l+S*p+I*A,e[3]=E*i+T*g+S*m+I*y,e[4]=(E=n[4])*r+(T=n[5])*a+(S=n[6])*u+(I=n[7])*d,e[5]=E*o+T*c+S*f+I*h,e[6]=E*s+T*l+S*p+I*A,e[7]=E*i+T*g+S*m+I*y,e[8]=(E=n[8])*r+(T=n[9])*a+(S=n[10])*u+(I=n[11])*d,e[9]=E*o+T*c+S*f+I*h,e[10]=E*s+T*l+S*p+I*A,e[11]=E*i+T*g+S*m+I*y,e[12]=(E=n[12])*r+(T=n[13])*a+(S=n[14])*u+(I=n[15])*d,e[13]=E*o+T*c+S*f+I*h,e[14]=E*s+T*l+S*p+I*A,e[15]=E*i+T*g+S*m+I*y,e}function ie(){var e=new re(9);return re!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}function ae(){var e=new re(3);return re!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function ce(e,t,n){var r=new re(3);return r[0]=e,r[1]=t,r[2]=n,r}function le(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e[2]=Math.min(t[2],n[2]),e}function ge(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e[2]=Math.max(t[2],n[2]),e}function ue(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e}function fe(e,t){var n=t[0],r=t[1],o=t[2],s=n*n+r*r+o*o;return s>0&&(s=1/Math.sqrt(s)),e[0]=t[0]*s,e[1]=t[1]*s,e[2]=t[2]*s,e}function pe(e,t,n){var r=t[0],o=t[1],s=t[2],i=n[3]*r+n[7]*o+n[11]*s+n[15];return e[0]=(n[0]*r+n[4]*o+n[8]*s+n[12])/(i=i||1),e[1]=(n[1]*r+n[5]*o+n[9]*s+n[13])/i,e[2]=(n[2]*r+n[6]*o+n[10]*s+n[14])/i,e}function me(e,t,n){var r=t[0],o=t[1],s=t[2];return e[0]=r*n[0]+o*n[3]+s*n[6],e[1]=r*n[1]+o*n[4]+s*n[7],e[2]=r*n[2]+o*n[5]+s*n[8],e}function de(){var e=new re(4);return re!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}function he(e,t,n=new Set){var r;const o=e.getAttribute("POSITION"),s=(null==(r=e.getIndices())?void 0:r.getArray())||Z(o.getCount());o&&Ae(t,o,s,new Set(n));const i=e.getAttribute("NORMAL");i&&ye(t,i,s,new Set(n));const a=e.getAttribute("TANGENT");a&&Ee(t,a,s,new Set(n));for(const r of e.listTargets()){const e=r.getAttribute("POSITION");e&&Ae(t,e,s,new Set(n));const o=r.getAttribute("NORMAL");o&&ye(t,o,s,new Set(n));const i=r.getAttribute("TANGENT");i&&Ee(t,i,s,new Set(n))}for(let e=0;e<s.length;e++)n.add(s[e])}function Ae(e,t,n,r){const o=new Float32Array(3*t.getCount()),s=t.getElementSize();for(let e=0,n=[],r=t.getCount();e<r;e++)o.set(t.getElement(e,n),e*s);const i=ae();for(let s=0;s<n.length;s++){const a=n[s];r.has(a)||(t.getElement(a,i),pe(i,i,e),o.set(i,3*a),r.add(a))}t.setArray(o).setNormalized(!1)}function ye(e,t,n,r){const o=ie();var s,i;(s=o)[0]=(i=e)[0],s[1]=i[1],s[2]=i[2],s[3]=i[4],s[4]=i[5],s[5]=i[6],s[6]=i[8],s[7]=i[9],s[8]=i[10],function(e,t){var n=t[0],r=t[1],o=t[2],s=t[3],i=t[4],a=t[5],c=t[6],l=t[7],g=t[8],u=g*i-a*l,f=-g*s+a*c,p=l*s-i*c,m=n*u+r*f+o*p;m&&(e[0]=u*(m=1/m),e[1]=(-g*r+o*l)*m,e[2]=(a*r-o*i)*m,e[3]=f*m,e[4]=(g*n-o*c)*m,e[5]=(-a*n+o*s)*m,e[6]=p*m,e[7]=(-l*n+r*c)*m,e[8]=(i*n-r*s)*m)}(o,o),function(e,t){if(e===t){var n=t[1],r=t[2],o=t[5];e[1]=t[3],e[2]=t[6],e[3]=n,e[5]=t[7],e[6]=r,e[7]=o}else e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8]}(o,o);const a=ae();for(let e=0;e<n.length;e++){const s=n[e];r.has(s)||(t.getElement(s,a),me(a,a,o),fe(a,a),t.setElement(s,a),r.add(s))}}function Ee(e,t,n,r){const o=ae(),s=de();for(let i=0;i<n.length;i++){const a=n[i];if(r.has(a))continue;t.getElement(a,s);const[c,l,g]=s;o[0]=e[0]*c+e[4]*l+e[8]*g,o[1]=e[1]*c+e[5]*l+e[9]*g,o[2]=e[2]*c+e[6]*l+e[10]*g,fe(o,o),s[0]=o[0],s[1]=o[1],s[2]=o[2],t.setElement(a,s),r.add(a)}}function Te(n,r,o=!1,i){for(const e of n.listPrimitives())if(e.listParents().some(e=>e.propertyType===t.MESH&&e!==n)){const t=e.clone();n.swap(e,t);for(const e of t.listTargets()){const n=e.clone();t.swap(e,n)}}if(!o){const t=new Set([...n.listPrimitives(),...n.listPrimitives().flatMap(e=>e.listTargets())]),r=new Map;for(const o of n.listPrimitives())for(const n of X(o))n.listParents().some(n=>(n instanceof e||n instanceof s)&&!t.has(n))&&!r.has(n)&&r.set(n,n.clone());for(const e of t)for(const[t,n]of r)e.swap(t,n)}i=i||new Set;for(const e of n.listPrimitives())he(e,r,i)}Math.hypot||(Math.hypot=function(){for(var e=0,t=arguments.length;t--;)e+=arguments[t]*arguments[t];return Math.sqrt(e)}),ae(),de();const Se=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];function Ie(e){const t=e.getMesh(),n=e.getMatrix();t&&!i.eq(n,Se)&&Te(t,n);for(const t of e.listChildren()){const e=t.getMatrix();se(e,e,n),t.setMatrix(e)}return e.setMatrix(Se)}const Me="colorspace";function we(e){return F(Me,t=>{const n=t.getLogger();if("linear"===e.inputEncoding)return void n.info(`${Me}: Vertex colors already linear. Skipping conversion.`);if("sRGB"!==e.inputEncoding)return void n.error(`${Me}: Unknown input encoding "${e.inputEncoding}" – should be "sRGB" or "linear". Skipping conversion.`);const r=new Set;function o(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function s(e){const t=[0,0,0];let n;for(let s=0;n=e.getAttribute(`COLOR_${s}`);s++)if(!r.has(n)){for(let e=0;e<n.getCount();e++)n.getElement(e,t),t[0]=o(t[0]),t[1]=o(t[1]),t[2]=o(t[2]),n.setElement(e,t);r.add(n)}}t.getRoot().listMeshes().forEach(e=>e.listPrimitives().forEach(s)),n.debug(`${Me}: Complete.`)})}const be={propertyTypes:[t.ACCESSOR,t.MESH,t.TEXTURE,t.MATERIAL]},Ne=function(e=be){const n=G({},be,e),r=new Set(n.propertyTypes);for(const e of n.propertyTypes)if(!be.propertyTypes.includes(e))throw new Error(`dedup: Unsupported deduplication on type "${e}".`);return F("dedup",e=>{const n=e.getLogger();r.has(t.ACCESSOR)&&function(e,t){const n=new Set,r=new Set,o=new Set,s=new Set,i=t.getRoot().listMeshes();i.forEach(e=>{e.listPrimitives().forEach(e=>{e.listAttributes().forEach(e=>r.add(e));const t=e.getIndices();t&&n.add(t)})});for(const e of t.getRoot().listAnimations())for(const t of e.listSamplers()){const e=t.getInput(),n=t.getOutput();e&&o.add(e),n&&s.add(n)}function c(e){const t=new Map;for(let n=0;n<e.length;n++){const r=e[n],o=a.toView(r.getArray());if(!t.has(r))for(let n=0;n<e.length;n++){const s=e[n];r!==s&&(t.has(s)||r.getType()===s.getType()&&r.getComponentType()===s.getComponentType()&&r.getCount()===s.getCount()&&r.getNormalized()===s.getNormalized()&&a.equals(o,a.toView(s.getArray()))&&t.set(s,r))}}return t}const l=c(Array.from(n));e.debug(`dedup: Found ${l.size} duplicates among ${n.size} indices.`);const g=c(Array.from(r));e.debug(`dedup: Found ${g.size} duplicates among ${r.size} attributes.`);const u=c(Array.from(o)),f=c(Array.from(s));e.debug(`dedup: Found ${u.size+f.size} duplicates among ${o.size+s.size} animation accessors.`),i.forEach(e=>{e.listPrimitives().forEach(e=>{e.listAttributes().forEach(t=>{g.has(t)&&e.swap(t,g.get(t))});const t=e.getIndices();t&&l.has(t)&&e.swap(t,l.get(t))})}),Array.from(l.keys()).forEach(e=>e.dispose()),Array.from(g.keys()).forEach(e=>e.dispose());for(const e of t.getRoot().listAnimations())for(const t of e.listSamplers()){const e=t.getInput(),n=t.getOutput();e&&u.has(e)&&t.swap(e,u.get(e)),n&&f.has(n)&&t.swap(n,f.get(n))}Array.from(u.keys()).forEach(e=>e.dispose()),Array.from(f.keys()).forEach(e=>e.dispose())}(n,e),r.has(t.TEXTURE)&&function(e,t){const n=t.getRoot(),r=n.listTextures(),o=new Map;for(let e=0;e<r.length;e++){const t=r[e],n=t.getImage();if(!o.has(t))for(let e=0;e<r.length;e++){const s=r[e],i=s.getImage();if(t===s)continue;if(o.has(s))continue;if(t.getMimeType()!==s.getMimeType())continue;const c=t.getSize(),l=s.getSize();c&&l&&c[0]===l[0]&&c[1]===l[1]&&n&&i&&a.equals(n,i)&&o.set(s,t)}}e.debug(`dedup: Found ${o.size} duplicates among ${n.listTextures().length} textures.`),Array.from(o.entries()).forEach(([e,t])=>{e.listParents().forEach(n=>{n instanceof c||n.swap(e,t)}),e.dispose()})}(n,e),r.has(t.MATERIAL)&&function(e,t){const n=t.getRoot(),r=n.listMaterials(),o=new Map,s=new Set(["name"]);for(let e=0;e<r.length;e++){const t=r[e];if(!o.has(t))for(let e=0;e<r.length;e++){const n=r[e];t!==n&&(o.has(n)||t.equals(n,s)&&o.set(n,t))}}e.debug(`dedup: Found ${o.size} duplicates among ${n.listMaterials().length} materials.`),Array.from(o.entries()).forEach(([e,t])=>{e.listParents().forEach(n=>{n instanceof c||n.swap(e,t)}),e.dispose()})}(n,e),r.has(t.MESH)&&function(e,n){const r=n.getRoot(),o=new Map;r.listAccessors().forEach((e,t)=>o.set(e,t)),r.listMaterials().forEach((e,t)=>o.set(e,t));const s=r.listMeshes().length,i=new Map;for(const e of r.listMeshes()){const n=[];for(const t of e.listPrimitives())n.push(Re(t,o));const r=n.join(";");if(i.has(r)){const n=i.get(r);e.listParents().forEach(r=>{r.propertyType!==t.ROOT&&r.swap(e,n)}),e.dispose()}else i.set(r,e)}e.debug(`dedup: Found ${s-i.size} duplicates among ${s} meshes.`)}(n,e),n.debug("dedup: Complete.")})};function Re(t,n){const r=[];for(const e of t.listSemantics()){const o=t.getAttribute(e);r.push(e+":"+n.get(o))}if(t instanceof e){const e=t.getIndices();e&&r.push("indices:"+n.get(e));const o=t.getMaterial();o&&r.push("material:"+n.get(o)),r.push("mode:"+t.getMode());for(const e of t.listTargets())r.push("target:"+Re(e,n))}return r.join(",")}const Ce={pattern:/^((?!JOINTS_).)*$/};function Oe(e=Ce){const t=G({},Ce,e);return F("dequantize",e=>{const n=e.getLogger();for(const n of e.getRoot().listMeshes())for(const e of n.listPrimitives())ve(e,t);e.createExtension(M).dispose(),n.debug("dequantize: Complete.")})}function ve(e,t){for(const n of e.listSemantics())Pe(n,e.getAttribute(n),t);for(const n of e.listTargets())for(const e of n.listSemantics())Pe(e,n.getAttribute(e),t)}function Pe(e,t,n){if(!t.getArray())return;if(!n.pattern.test(e))return;if(t.getComponentSize()>=4)return;const r=t.getArray(),o=new Float32Array(r.length);for(let e=0,n=t.getCount(),s=[];e<n;e++)s=t.getElement(e,s),t.setArray(o).setElement(e,s).setArray(r);t.setArray(o).setNormalized(!1)}const $e={method:"edgebreaker",encodeSpeed:5,decodeSpeed:5,quantizePosition:14,quantizeNormal:10,quantizeColor:8,quantizeTexcoord:12,quantizeGeneric:12,quantizationVolume:"mesh"},xe=(e=$e)=>{const t=G({},$e,e);return F("draco",e=>{e.createExtension(w).setRequired(!0).setEncoderOptions({method:"edgebreaker"===t.method?w.EncoderMethod.EDGEBREAKER:w.EncoderMethod.SEQUENTIAL,encodeSpeed:t.encodeSpeed,decodeSpeed:t.decodeSpeed,quantizationBits:{POSITION:t.quantizePosition,NORMAL:t.quantizeNormal,COLOR:t.quantizeColor,TEX_COORD:t.quantizeTexcoord,GENERIC:t.quantizeGeneric},quantizationVolume:t.quantizationVolume})})},ze={propertyTypes:[t.NODE,t.SKIN,t.MESH,t.CAMERA,t.PRIMITIVE,t.PRIMITIVE_TARGET,t.ANIMATION,t.MATERIAL,t.TEXTURE,t.ACCESSOR,t.BUFFER],keepLeaves:!1,keepAttributes:!0},Le=function(e=ze){const n=G({},ze,e),r=new Set(n.propertyTypes);return F("prune",e=>{const s=e.getLogger(),i=e.getRoot(),a=e.getGraph(),g={};if(r.has(t.MESH))for(const e of i.listMeshes())e.listPrimitives().length>0||(e.dispose(),m(e));if(r.has(t.NODE)&&!n.keepLeaves&&i.listScenes().forEach(function e(n){if(n.listChildren().forEach(e),n instanceof o)return;const r=a.listParentEdges(n).some(e=>{const n=e.getParent().propertyType;return n!==t.ROOT&&n!==t.SCENE&&n!==t.NODE});0!==a.listChildren(n).length||r||(n.dispose(),m(n))}),r.has(t.NODE)&&i.listNodes().forEach(u),r.has(t.SKIN)&&i.listSkins().forEach(u),r.has(t.MESH)&&i.listMeshes().forEach(u),r.has(t.CAMERA)&&i.listCameras().forEach(u),r.has(t.PRIMITIVE)&&f(a,t.PRIMITIVE),r.has(t.PRIMITIVE_TARGET)&&f(a,t.PRIMITIVE_TARGET),!n.keepAttributes&&r.has(t.ACCESSOR))for(const t of i.listMeshes())for(const n of t.listPrimitives()){const t=_e(e,n.getMaterial()),r=qe(n,t);p(n,r),n.listTargets().forEach(e=>p(e,r))}if(r.has(t.ANIMATION))for(const e of i.listAnimations()){for(const t of e.listChannels())t.getTargetNode()||(t.dispose(),m(t));if(e.listChannels().length)e.listSamplers().forEach(u);else{const t=e.listSamplers();u(e),t.forEach(u)}}if(r.has(t.MATERIAL)&&i.listMaterials().forEach(u),r.has(t.TEXTURE)&&i.listTextures().forEach(u),r.has(t.ACCESSOR)&&i.listAccessors().forEach(u),r.has(t.BUFFER)&&i.listBuffers().forEach(u),Object.keys(g).length){const e=Object.keys(g).map(e=>`${e} (${g[e]})`).join(", ");s.info(`prune: Removed types... ${e}`)}else s.info("prune: No unused properties found.");function u(e){e.listParents().filter(e=>!(e instanceof c||e instanceof l)).length||(e.dispose(),m(e))}function f(e,t){e.listEdges().map(e=>e.getParent()).filter(e=>e.propertyType===t).forEach(u)}function p(e,t){for(const n of t)e.setAttribute(n,null)}function m(e){g[e.propertyType]=g[e.propertyType]||0,g[e.propertyType]++}s.debug("prune: Complete.")})};function qe(e,t){const n=[];for(const r of e.listSemantics())"TANGENT"!==r||t.has(r)?(r.startsWith("TEXCOORD_")&&!t.has(r)||r.startsWith("COLOR_")&&"COLOR_0"!==r)&&n.push(r):n.push(r);return n}function _e(e,t,n=new Set){if(!t)return n;const r=e.getGraph().listChildEdges(t),o=new Set;for(const e of r)e.getChild()instanceof g&&o.add(e.getName());for(const t of r){const r=t.getName(),s=t.getChild();s instanceof u&&o.has(r.replace(/Info$/,""))&&n.add(`TEXCOORD_${s.getTexCoord()}`),s instanceof g&&r.match(/normalTexture/i)&&n.add("TANGENT"),s instanceof f&&_e(e,s,n)}return n}const ke={};function Ge(e=ke){return G({},ke,e),F("flatten",async e=>{const n=e.getRoot(),r=e.getLogger(),o=new Set;for(const e of n.listSkins())for(const t of e.listJoints())o.add(t);const s=new Set;for(const e of n.listAnimations())for(const t of e.listChannels()){const e=t.getTargetNode();e&&s.add(e)}const i=new Set,a=new Set;for(const e of n.listScenes())e.traverse(e=>{const t=e.getParentNode();t&&((o.has(t)||i.has(t))&&i.add(e),(s.has(t)||a.has(t))&&a.add(e))});for(const e of n.listScenes())e.traverse(e=>{s.has(e)||i.has(e)||a.has(e)||ne(e)});s.size&&r.debug("flatten: Flattening node hierarchies with TRS animation not yet supported."),await e.transform(Le({propertyTypes:[t.NODE],keepLeaves:!1})),r.debug("flatten: Complete.")})}function Fe(e){return te(e)[0]||null}function Be(e){return{scenes:Ue(e),meshes:We(e),materials:He(e),textures:je(e),animations:De(e)}}function Ue(e){return{properties:e.getRoot().listScenes().map(e=>{const t=e.listChildren()[0],n=r(e);return{name:e.getName(),rootName:t?t.getName():"",bboxMin:Ke(n.min),bboxMax:Ke(n.max)}})}}function We(e){return{properties:e.getRoot().listMeshes().map(e=>{const n=e.listParents().filter(e=>e.propertyType!==t.ROOT).length;let r=0,o=0;const s=new Set,i=new Set,a=new Set;e.listPrimitives().forEach(e=>{for(const t of e.listSemantics()){const n=e.getAttribute(t);s.add(t+":"+Je(n)),a.add(n)}for(const t of e.listTargets())t.listAttributes().forEach(e=>a.add(e));const t=e.getIndices();t&&(i.add(Je(t)),a.add(t)),o+=e.listAttributes()[0].getCount(),r+=W(e)});let c=0;Array.from(a).forEach(e=>c+=e.getArray().byteLength);const l=e.listPrimitives().map(e=>Ve[e.getMode()]);return{name:e.getName(),mode:Array.from(new Set(l)),primitives:e.listPrimitives().length,glPrimitives:r,vertices:o,indices:Array.from(i).sort(),attributes:Array.from(s).sort(),instances:n,size:c}})}}function He(e){return{properties:e.getRoot().listMaterials().map(n=>{const r=n.listParents().filter(e=>e.propertyType!==t.ROOT).length,o=new Set(n.listExtensions()),s=e.getGraph().listEdges().filter(e=>{const t=e.getChild(),r=e.getParent();return t instanceof g&&r===n||!!(t instanceof g&&r instanceof f&&o.has(r))}).map(e=>e.getName());return{name:n.getName(),instances:r,textures:s,alphaMode:n.getAlphaMode(),doubleSided:n.getDoubleSided()}})}}function je(e){return{properties:e.getRoot().listTextures().map(n=>{const r=n.listParents().filter(e=>e.propertyType!==t.ROOT).length,o=e.getGraph().listParentEdges(n).filter(e=>e.getParent().propertyType!==t.ROOT).map(e=>e.getName()),s=p.getSize(n.getImage(),n.getMimeType());let i="";if("image/ktx2"===n.getMimeType()){const e=x(n.getImage()).dataFormatDescriptor[0];e.colorModel===z?i="ETC1S":e.colorModel===L&&(i="UASTC")}return{name:n.getName(),uri:n.getURI(),slots:Array.from(new Set(o)),instances:r,mimeType:n.getMimeType(),compression:i,resolution:s?s.join("x"):"",size:n.getImage().byteLength,gpuSize:p.getVRAMByteLength(n.getImage(),n.getMimeType())}})}}function De(e){return{properties:e.getRoot().listAnimations().map(e=>{let t=Infinity,n=-Infinity;e.listSamplers().forEach(e=>{const r=e.getInput();r&&(t=Math.min(t,r.getMin([])[0]),n=Math.max(n,r.getMax([])[0]))});let r=0,o=0;const s=new Set;return e.listSamplers().forEach(e=>{const t=e.getInput(),n=e.getOutput();t&&(o+=t.getCount(),s.add(t),n&&s.add(n))}),Array.from(s).forEach(e=>{r+=e.getArray().byteLength}),{name:e.getName(),channels:e.listChannels().length,samplers:e.listSamplers().length,duration:Math.round(1e3*(n-t))/1e3,keyframes:o,size:r}})}}const Ve=["POINTS","LINES","LINE_LOOP","LINE_STRIP","TRIANGLES","TRIANGLE_STRIP","TRIANGLE_FAN"],Xe={Float32Array:"f32",Uint32Array:"u32",Uint16Array:"u16",Uint8Array:"u8",Int32Array:"i32",Int16Array:"i16",Int8Array:"i8"};function Ke(e){for(let t=0;t<e.length;t++)e[t].toFixed&&(e[t]=Number(e[t].toFixed(5)));return e}function Je(e){const t=e.getArray();return(Xe[t.constructor.name]||"?")+(e.getNormalized()?"_norm":"")}const Ze={min:2};function Qe(e=Ze){const t=G({},Ze,e);return F("instance",e=>{const n=e.getLogger(),r=e.getRoot(),o=e.createExtension(b);if(r.listAnimations().length)return n.warn("instance: Instancing is not currently supported for animated models."),void n.debug("instance: Complete.");let s=0,a=0;for(const c of r.listScenes()){const r=new Map;c.traverse(e=>{const t=e.getMesh();t&&r.set(t,(r.get(t)||new Set).add(e))});const l=[];for(const g of Array.from(r.keys())){const u=Array.from(r.get(g));if(u.length<t.min)continue;if(u.some(e=>e.getSkin()))continue;const f=et(e,o,g,u.length),p=f.getAttribute("TRANSLATION"),m=f.getAttribute("ROTATION"),d=f.getAttribute("SCALE"),h=e.createNode().setMesh(g).setExtension("EXT_mesh_gpu_instancing",f);c.addChild(h);let A=!1,y=!1,E=!1;for(let e=0;e<u.length;e++){let t,n,r;const o=u[e];p.setElement(e,t=o.getWorldTranslation()),m.setElement(e,n=o.getWorldRotation()),d.setElement(e,r=o.getWorldScale()),i.eq(t,[0,0,0])||(A=!0),i.eq(n,[0,0,0,1])||(y=!0),i.eq(r,[1,1,1])||(E=!0),o.setMesh(null),l.push(o)}A||p.dispose(),y||m.dispose(),E||d.dispose(),Ye(l,n),s++,a+=u.length}}n.info(s>0?`instance: Created ${s} batches, with ${a} total instances.`:`instance: No meshes with ≥${t.min} parent nodes were found.`),0===o.listProperties().length&&o.dispose(),n.debug("instance: Complete.")})}function Ye(e,t){let n,r=0;for(;n=e.pop();){if(n.listChildren().length||n.getCamera()||n.getMesh()||n.getSkin()||n.listExtensions().length)continue;const t=n.getParentNode();t&&e.push(t),n.dispose(),r++}t.debug(`instance: Removed ${r} unused nodes.`)}function et(e,t,n,r){const o=n.listPrimitives()[0].getAttribute("POSITION").getBuffer(),s=e.createAccessor().setType("VEC3").setArray(new Float32Array(3*r)).setBuffer(o),i=e.createAccessor().setType("VEC4").setArray(new Float32Array(4*r)).setBuffer(o),a=e.createAccessor().setType("VEC3").setArray(new Float32Array(3*r)).setBuffer(o);return t.createInstancedMesh().setAttribute("TRANSLATION",s).setAttribute("ROTATION",i).setAttribute("SCALE",a)}const tt={skipValidation:!1};function nt(e,t={}){t=G({},tt,t);const r=e[0],o=n.fromGraph(r.getGraph());if(!t.skipValidation&&new Set(e.map(Q)).size>1)throw new Error("Requires ≥2 Primitives, sharing the same Material and Mode, with compatible vertex attributes and indices.");const s=[],i=[];let a=0,c=0;for(const t of e){const e=rt(t),n=[];for(let t=0;t<e.length;t++){const r=e[t];void 0===n[r]&&(n[r]=a++),c++}s.push(new Uint32Array(n)),i.push(e)}const l=o.createPrimitive().setMode(r.getMode()).setMaterial(r.getMaterial());for(const e of r.listSemantics()){const t=r.getAttribute(e),n=m[t.getComponentType()],s=o.createAccessor().setType(t.getType()).setBuffer(t.getBuffer()).setNormalized(t.getNormalized()).setArray(new n(a*t.getElementSize()));l.setAttribute(e,s)}const g=(r.getIndices()?Z(a):null)&&o.createAccessor().setBuffer(r.getIndices().getBuffer()).setArray(Z(c,a));l.setIndices(g);let u=0;for(let t=0;t<s.length;t++){const n=e[t],r=s[t],o=i[t],a=u;let c=a;for(const e of l.listSemantics()){const t=n.getAttribute(e),s=l.getAttribute(e),i=[];c=a;for(let e=0;e<o.length;e++){const n=o[e];t.getElement(n,i),s.setElement(r[n],i),g&&g.setScalar(c++,r[n])}}u=c}return l}function rt(e){const t=e.getIndices();return t?t.getArray():Z(e.getAttribute("POSITION").getCount())}const{ROOT:ot,NODE:st,MESH:it,PRIMITIVE:at,ACCESSOR:ct}=t,lt=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],gt={keepMeshes:!1,keepNamed:!1};function ut(e=gt){const t=G({},gt,e);return F("join",async e=>{const n=e.getRoot(),r=e.getLogger();for(const r of n.listScenes())ft(e,r,t),r.traverse(n=>ft(e,n,t));await e.transform(Le({propertyTypes:[st,it,at,ct],keepLeaves:!1,keepAttributes:!0})),r.debug("join: Complete.")})}function ft(e,n,r){const o=e.getLogger(),s={},i=n.listChildren();for(let e=0;e<i.length;e++){const t=i[e];if(t.listParents().some(e=>e instanceof l))continue;const n=t.getMesh();if(n&&!t.getExtension("EXT_mesh_gpu_instancing")&&!t.getSkin())for(const o of n.listPrimitives()){if(o.listTargets().length>0)continue;const i=o.getMaterial();if(i&&i.getExtension("KHR_materials_volume"))continue;let a=Q(o);const c=n.getName()||t.getName();(r.keepMeshes||r.keepNamed&&c)&&(a+=`|${e}`),a in s||(s[a]={prims:[],primMeshes:[],primNodes:[],dstNode:t,dstMesh:void 0});const l=s[a];l.prims.push(o),l.primNodes.push(t)}}const a=Object.values(s).filter(({prims:e})=>e.length>1),c=new Set(a.flatMap(e=>e.primNodes));for(const e of c){const t=e.getMesh();t.listParents().some(t=>t.propertyType!==ot&&e!==t)&&e.setMesh(t.clone())}for(const e of a){const{dstNode:t,primNodes:n}=e;e.dstMesh=t.getMesh(),e.primMeshes=n.map(e=>e.getMesh())}for(const e of a){const{prims:n,primNodes:r,primMeshes:s,dstNode:i,dstMesh:a}=e,c=i.getMatrix();for(let e=0;e<n.length;e++){const o=r[e];let a=n[e];s[e].removePrimitive(a),(a.listParents().some(e=>e.propertyType!==t.ROOT)||mt(a))&&(a=n[e]=pt(n[e])),o!==i&&(se(lt,oe(lt,c),o.getMatrix()),he(a,lt))}const l=nt(n),g=l.listAttributes()[0].getCount();a.addPrimitive(l),o.debug(`join: Joined Primitives (${n.length}) containing ${D(g)} vertices under Node "${i.getName()}".`)}}function pt(e){const t=e.clone();for(const e of t.listSemantics())t.setAttribute(e,t.getAttribute(e).clone());const n=t.getIndices();return n&&t.setIndices(n.clone()),t}function mt(e){for(const t of e.listAttributes())for(const n of t.listParents())if(n!==e&&n.propertyType!==ot)return!0;return!1}function dt(e){const t=ht(e),n=[];return t&h.R&&n.push(h.R),t&h.G&&n.push(h.G),t&h.B&&n.push(h.B),t&h.A&&n.push(h.A),n}function ht(e){const r=n.fromGraph(e.getGraph());let o=0;for(const n of r.getGraph().listParentEdges(e)){const e=n.getParent();let{channels:s}=n.getAttributes();s&&"baseColorTexture"===n.getName()&&e instanceof d&&e.getAlphaMode()===d.AlphaMode.OPAQUE&&(s&=~h.A),s?o|=s:e.propertyType!==t.ROOT&&r.getLogger().warn(`Missing attribute ".channels" on edge, "${n.getName()}".`)}return o}function At(e){const t=e.getGraph(),n=[];for(const r of t.listParentEdges(e)){const e=r.getParent(),o=r.getName()+"Info";for(const r of t.listChildEdges(e)){const e=r.getChild();e instanceof u&&r.getName()===o&&n.push(e)}}return n}function yt(e){const t=n.fromGraph(e.getGraph()).getRoot(),r=e.getGraph().listParentEdges(e).filter(e=>e.getParent()!==t).map(e=>e.getName());return Array.from(new Set(r))}const Et={target:"size"};function Tt(n){const r=G({},Et,n),o=r.encoder;if(!o)throw new Error('reorder: encoder dependency required — install "meshoptimizer".');return F("reorder",async n=>{const s=n.getLogger();await o.ready;const i=St(n);for(const t of i.indicesToAttributes.keys()){const n=t.clone();let s=n.getArray().slice();s instanceof Uint32Array||(s=new Uint32Array(s));const[a,c]=o.reorderMesh(s,i.indicesToMode.get(t)===e.Mode.TRIANGLES,"size"===r.target);n.setArray(c<=65534?new Uint16Array(s):s);for(const e of i.indicesToAttributes.get(t)){const r=e.clone();J(r,a,c);for(const o of i.attributesToPrimitives.get(e))if(o.getIndices()===t&&o.swap(t,n),o.getIndices()===n){o.swap(e,r);for(const t of o.listTargets())t.swap(e,r)}}}await n.transform(Le({propertyTypes:[t.ACCESSOR]})),i.indicesToAttributes.size?s.debug("reorder: Complete."):s.warn("reorder: No qualifying primitives found; may need to weld first.")})}function St(e){const t=new H,n=new Map,r=new H;for(const o of e.getRoot().listMeshes())for(const e of o.listPrimitives()){const o=e.getIndices();if(o){n.set(o,e.getMode());for(const n of X(e))t.add(o,n),r.add(n,e)}}return{indicesToAttributes:t,indicesToMode:n,attributesToPrimitives:r}}function It(e,t=Infinity){if(Number.isFinite(t)&&t%4||t<=0)throw new Error("Limit must be positive multiple of four.");const n=e.getAttribute("POSITION").getCount(),r=e.listSemantics().filter(e=>e.startsWith("WEIGHTS_")).length,o=new Uint16Array(4*r),s=new Float32Array(4*r),a=new Float32Array(4*r),c=new Uint32Array(4*r),l=new Uint32Array(4*r);for(let t=0;t<n;t++){Mt(e,t,"WEIGHTS",s),Mt(e,t,"JOINTS",c);for(let e=0;e<4*r;e++)o[e]=e;o.sort((e,t)=>s[e]>s[t]?-1:1);for(let e=0;e<o.length;e++)a[e]=s[o[e]],l[e]=c[o[e]];wt(e,t,"WEIGHTS",a),wt(e,t,"JOINTS",l)}for(let n=r;4*n>t;n--){const t=e.getAttribute("WEIGHTS_"+(n-1)),r=e.getAttribute("JOINTS_"+(n-1));e.setAttribute("WEIGHTS_"+(n-1),null),e.setAttribute("JOINTS_"+(n-1),null),1===t.listParents().length&&t.dispose(),1===r.listParents().length&&r.dispose()}!function(e){if(!function(e){const t=e.listSemantics().filter(e=>e.startsWith("WEIGHTS_")).map(t=>e.getAttribute(t)),n=t.map(e=>e.getNormalized()),r=t.map(e=>e.getComponentType());return 1===new Set(n).size&&1===new Set(r).size}(e))return;const t=e.getAttribute("POSITION").getCount(),n=e.listSemantics().filter(e=>e.startsWith("WEIGHTS_")).length,r=e.getAttribute("WEIGHTS_0"),o=r.getArray(),s=r.getComponentType(),a=r.getNormalized(),c=a?s:void 0,l=a?i.decodeNormalizedInt(1,s):Number.EPSILON,g=new Uint32Array(4*n).fill(0),u=o.slice(0,4*n).fill(0);for(let n=0;n<t;n++){Mt(e,n,"JOINTS",g),Mt(e,n,"WEIGHTS",u,c);let t=bt(u,c);if(0!==t){if(Math.abs(1-t)>l)for(let e=0;e<u.length;e++)if(a){const n=i.encodeNormalizedInt(u[e]/t,s);u[e]=i.decodeNormalizedInt(n,s)}else u[e]/=t;if(t=bt(u,c),a&&1!==t)for(let e=u.length-1;e>=0;e--)if(u[e]>0){u[e]+=i.encodeNormalizedInt(1-t,s);break}for(let e=u.length-1;e>=0;e--)0===u[e]&&(g[e]=0);wt(e,n,"JOINTS",g),wt(e,n,"WEIGHTS",u,c)}}}(e)}function Mt(e,t,n,r,o){let s;const a=[0,0,0,0];for(let c=0;s=e.getAttribute(`${n}_${c}`);c++){s.getElement(t,a);for(let e=0;e<4;e++)r[4*c+e]=o?i.encodeNormalizedInt(a[e],o):a[e]}return r}function wt(e,t,n,r,o){let s;const a=[0,0,0,0];for(let c=0;s=e.getAttribute(`${n}_${c}`);c++){for(let e=0;e<4;e++)a[e]=o?i.decodeNormalizedInt(r[4*c+e],o):r[4*c+e];s.setElement(t,a)}}function bt(e,t){let n=0;for(let r=0;r<e.length;r++)n+=t?i.decodeNormalizedInt(e[r],t):e[r];return n}const Nt=[Int8Array,Int16Array,Int32Array],{TRANSLATION:Rt,ROTATION:Ct,SCALE:Ot,WEIGHTS:vt}=l.TargetPath,Pt=[Rt,Ct,Ot],$t={pattern:/.*/,quantizationVolume:"mesh",quantizePosition:14,quantizeNormal:10,quantizeTexcoord:12,quantizeColor:8,quantizeWeight:8,quantizeGeneric:12,normalizeWeights:!0},xt=(e=$t)=>{const n=G({},$t,e);return F("quantize",async e=>{const r=e.getLogger(),o=e.getRoot();let s;e.createExtension(M).setRequired(!0),"scene"===n.quantizationVolume&&(s=Lt(function(e){const t=e[0];for(const n of e)le(t.min,t.min,n.min),ge(t.max,t.max,n.max);return t}(o.listMeshes().map(Bt))));for(const t of e.getRoot().listMeshes()){"mesh"===n.quantizationVolume&&(s=Lt(Bt(t))),s&&n.pattern.test("POSITION")&&(qt(e,t,s),kt(t,1/s.scale));for(const r of t.listPrimitives()){zt(e,r,s,n);for(const t of r.listTargets())zt(e,t,s,n)}}await e.transform(Le({propertyTypes:[t.ACCESSOR,t.SKIN,t.MATERIAL]}),Ne({propertyTypes:[t.ACCESSOR,t.MATERIAL]})),r.debug("quantize: Complete.")})};function zt(t,n,r,o){const s=t.getLogger();for(const t of n.listSemantics()){if(!o.pattern.test(t))continue;const c=n.getAttribute(t),{bits:l,ctor:g}=Ft(t,c,s,o);if(!g)continue;if(l<8||l>16)throw new Error("quantize: Requires bits = 8–16.");if(c.getComponentSize()<=l/8)continue;const u=c.clone();if("POSITION"===t){const t=r.scale,o=[];n instanceof e?oe(o,Wt(r)):((i=o)[0]=(a=[1/t,1/t,1/t])[0],i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=a[1],i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=a[2],i[11]=0,i[12]=0,i[13]=0,i[14]=0,i[15]=1);for(let e=0,t=[0,0,0],n=u.getCount();e<n;e++)u.getElement(e,t),u.setElement(e,pe(t,t,o))}Gt(u,g,l),n.swap(c,u)}var i,a;if(o.normalizeWeights&&n.getAttribute("WEIGHTS_0")&&It(n,Infinity),n instanceof e&&n.getIndices()&&n.listAttributes().length&&n.listAttributes()[0].getCount()<65535){const e=n.getIndices();e.setArray(new Uint16Array(e.getArray()))}}function Lt(e){const{min:t,max:n}=e,r=Math.max((n[0]-t[0])/2,(n[1]-t[1])/2,(n[2]-t[2])/2);return{offset:[t[0]+(n[0]-t[0])/2,t[1]+(n[1]-t[1])/2,t[2]+(n[2]-t[2])/2],scale:r}}function qt(e,t,n){const r=Wt(n);for(const o of t.listParents()){if(!(o instanceof A))continue;const s=o.listParents().filter(e=>e instanceof l),i=s.some(e=>Pt.includes(e.getTargetPath())),a=o.listChildren().length>0;if(o.getSkin()){o.setSkin(_t(o.getSkin(),n));continue}let c;a||i?(c=e.createNode("").setMesh(t),o.addChild(c).setMesh(null),s.filter(e=>e.getTargetPath()===vt).forEach(e=>e.setTargetNode(c))):c=o;const g=c.getMatrix();se(g,g,r),c.setMatrix(g)}}function _t(e,t){e=e.clone();const n=Wt(t),r=e.getInverseBindMatrices().clone(),o=[];for(let e=0,t=r.getCount();e<t;e++)r.getElement(e,o),se(o,o,n),r.setElement(e,o);return e.setInverseBindMatrices(r)}function kt(e,t){for(const n of e.listPrimitives()){let e=n.getMaterial();if(!e)continue;let r=e.getExtension("KHR_materials_volume");!r||r.getThicknessFactor()<=0||(r=r.clone().setThicknessFactor(r.getThicknessFactor()*t),e=e.clone().setExtension("KHR_materials_volume",r),n.setMaterial(e))}}function Gt(e,t,n){const r=new t(e.getArray().length),o=Nt.includes(t)?1:0,s=n-o,i=8*t.BYTES_PER_ELEMENT-o,a=Math.pow(2,s)-1,c=i-s,l=2*s-i;for(let t=0,n=0,o=[];t<e.getCount();t++){e.getElement(t,o);for(let e=0;e<o.length;e++){let t=Math.round(Math.abs(o[e])*a);t=t<<c|t>>l,r[n++]=t*Math.sign(o[e])}}e.setArray(r).setNormalized(!0).setSparse(!1)}function Ft(e,t,n,r){const o=t.getMinNormalized([]),s=t.getMaxNormalized([]);let i,a;if("POSITION"===e)i=r.quantizePosition,a=i<=8?Int8Array:Int16Array;else if("NORMAL"===e||"TANGENT"===e)i=r.quantizeNormal,a=i<=8?Int8Array:Int16Array;else if(e.startsWith("COLOR_"))i=r.quantizeColor,a=i<=8?Uint8Array:Uint16Array;else if(e.startsWith("TEXCOORD_")){if(o.some(e=>e<0)||s.some(e=>e>1))return n.warn(`quantize: Skipping ${e}; out of [0,1] range.`),{bits:-1};i=r.quantizeTexcoord,a=i<=8?Uint8Array:Uint16Array}else{if(e.startsWith("JOINTS_"))return i=Math.max(...t.getMax([]))<=255?8:16,a=i<=8?Uint8Array:Uint16Array,t.getComponentSize()>i/8&&t.setArray(new a(t.getArray())),{bits:-1};if(e.startsWith("WEIGHTS_")){if(o.some(e=>e<0)||s.some(e=>e>1))return n.warn(`quantize: Skipping ${e}; out of [0,1] range.`),{bits:-1};i=r.quantizeWeight,a=i<=8?Uint8Array:Uint16Array}else{if(!e.startsWith("_"))throw new Error(`quantize: Unexpected semantic, "${e}".`);if(o.some(e=>e<-1)||s.some(e=>e>1))return n.warn(`quantize: Skipping ${e}; out of [-1,1] range.`),{bits:-1};i=r.quantizeGeneric,a=a=o.some(e=>e<0)?i<=8?Int8Array:Int16Array:i<=8?Uint8Array:Uint16Array}}return{bits:i,ctor:a}}function Bt(e){const t=[],n=[];for(const r of e.listPrimitives()){const e=r.getAttribute("POSITION");e&&t.push(e);for(const e of r.listTargets()){const t=e.getAttribute("POSITION");t&&n.push(t)}}if(0===t.length)throw new Error('quantize: Missing "POSITION" attribute.');const r=Ut(t,3);if(n.length>0){const{min:e,max:t}=Ut(n,3);le(r.min,r.min,le(e,ue(e,e,2),[0,0,0])),ge(r.max,r.max,ge(t,ue(t,t,2),[0,0,0]))}return r}function Ut(e,t){const n=new Array(t).fill(Infinity),r=new Array(t).fill(-Infinity),o=[],s=[];for(const i of e){i.getMinNormalized(o),i.getMaxNormalized(s);for(let e=0;e<t;e++)n[e]=Math.min(n[e],o[e]),r[e]=Math.max(r[e],s[e])}return{min:n,max:r}}function Wt(e){return r=e.offset,f=(s=(n=[0,0,0,1])[0])*(l=s+s),p=s*(g=(i=n[1])+i),m=s*(u=(a=n[2])+a),h=i*u,y=(c=n[3])*l,E=c*g,T=c*u,I=(o=[e.scale,e.scale,e.scale])[1],M=o[2],(t=[])[0]=(1-((d=i*g)+(A=a*u)))*(S=o[0]),t[1]=(p+T)*S,t[2]=(m-E)*S,t[3]=0,t[4]=(p-T)*I,t[5]=(1-(f+A))*I,t[6]=(h+y)*I,t[7]=0,t[8]=(m+E)*M,t[9]=(h-y)*M,t[10]=(1-(f+d))*M,t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t;var t,n,r,o,s,i,a,c,l,g,u,f,p,m,d,h,A,y,E,T,S,I,M}const Ht={level:"high"},jt=e=>{const t=G({},Ht,e),n=t.encoder;if(!n)throw new Error('meshopt: encoder dependency required — install "meshoptimizer".');return F("meshopt",async e=>{await e.transform(Tt({encoder:n,target:"size"}),xt({pattern:"medium"===t.level?/.*/:/^(POSITION|TEXCOORD|JOINTS|WEIGHTS)(_\d+)?$/,quantizePosition:14,quantizeTexcoord:12,quantizeColor:8,quantizeNormal:8})),e.createExtension(N).setRequired(!0).setEncoderOptions({method:"medium"===t.level?N.EncoderMethod.QUANTIZE:N.EncoderMethod.FILTER})})},Dt={};function Vt(e=Dt){return G({},Dt,e),F("metalRough",async e=>{const t=e.getLogger();if(!e.getRoot().listExtensionsUsed().map(e=>e.extensionName).includes("KHR_materials_pbrSpecularGlossiness"))return void t.warn("metalRough: KHR_materials_pbrSpecularGlossiness not found on document.");const n=e.createExtension(R),r=e.createExtension(C),o=e.createExtension(O),s=new Set;for(const t of e.getRoot().listMaterials()){const o=t.getExtension("KHR_materials_pbrSpecularGlossiness");if(!o)continue;const i=r.createSpecular().setSpecularFactor(1).setSpecularColorFactor(o.getSpecularFactor());s.add(o.getSpecularGlossinessTexture()),s.add(t.getBaseColorTexture()),s.add(t.getMetallicRoughnessTexture()),t.setBaseColorFactor(o.getDiffuseFactor()).setMetallicFactor(0).setRoughnessFactor(1).setExtension("KHR_materials_ior",n.createIOR().setIOR(1e3)).setExtension("KHR_materials_specular",i);const a=o.getDiffuseTexture();a&&(t.setBaseColorTexture(a),t.getBaseColorTextureInfo().copy(o.getDiffuseTextureInfo()));const c=o.getSpecularGlossinessTexture();if(c){const n=o.getSpecularGlossinessTextureInfo(),r=e.createTexture();await U(c,r,(e,t,n)=>{e.set(t,n,3,255)}),i.setSpecularTexture(r),i.setSpecularColorTexture(r),i.getSpecularTextureInfo().copy(n),i.getSpecularColorTextureInfo().copy(n);const s=o.getGlossinessFactor(),a=e.createTexture();await U(c,a,(e,t,n)=>{const r=255-Math.round(e.get(t,n,3)*s);e.set(t,n,0,0),e.set(t,n,1,r),e.set(t,n,2,0),e.set(t,n,3,255)}),t.setMetallicRoughnessTexture(a),t.getMetallicRoughnessTextureInfo().copy(n)}else i.setSpecularColorFactor(o.getSpecularFactor()),t.setRoughnessFactor(1-o.getGlossinessFactor());t.setExtension("KHR_materials_pbrSpecularGlossiness",null)}o.dispose();for(const e of s)e&&1===e.listParents().length&&e.dispose();t.debug("metalRough: Complete.")})}const Xt={};function Kt(e=Xt){return G({},Xt,e),F("unweld",e=>{const t=e.getLogger(),n=new Map;for(const r of e.getRoot().listMeshes())for(const e of r.listPrimitives()){const r=e.getIndices();if(!r)continue;const o=e.getAttribute("POSITION").getCount();for(const o of e.listAttributes())e.swap(o,Jt(o,r,t,n)),1===o.listParents().length&&o.dispose();for(const o of e.listTargets())for(const e of o.listAttributes())o.swap(e,Jt(e,r,t,n)),1===e.listParents().length&&e.dispose();const s=e.getAttribute("POSITION").getCount();t.debug(`unweld: ${V(o,s)} vertices.`),e.setIndices(null),1===r.listParents().length&&r.dispose()}t.debug("unweld: Complete.")})}function Jt(e,t,n,r){if(r.has(e)&&r.get(e).has(t))return n.debug(`unweld: Cache hit for reused attribute, "${e.getName()}".`),r.get(e).get(t);const o=e.clone(),s=e.getArray().constructor;o.setArray(new s(t.getCount()*e.getElementSize()));const i=[];for(let n=0;n<t.getCount();n++)o.setElement(n,e.getElement(t.getScalar(n),i));return r.has(e)||r.set(e,new Map),r.get(e).set(t,o),o}const Zt={overwrite:!1};function Qt(e=Zt){const t=G({},Zt,e);return F("normals",async e=>{const n=e.getLogger();let r=0;await e.transform(Kt());for(const o of e.getRoot().listMeshes())for(const s of o.listPrimitives()){const o=s.getAttribute("POSITION");let i=s.getAttribute("NORMAL");if(t.overwrite&&i)i.dispose();else if(i){n.debug("normals: Skipping primitive: NORMAL found.");continue}i=e.createAccessor().setArray(new Float32Array(3*o.getCount())).setType("VEC3");const a=[0,0,0],c=[0,0,0],l=[0,0,0];for(let e=0;e<o.getCount();e+=3){o.getElement(e+0,a),o.getElement(e+1,c),o.getElement(e+2,l);const t=Yt(a,c,l);i.setElement(e+0,t),i.setElement(e+1,t),i.setElement(e+2,t)}s.setAttribute("NORMAL",i),r++}r?n.debug("normals: Complete."):n.warn("normals: No qualifying primitives found. See debug output.")})}function Yt(e,t,n){const r=[t[0]-e[0],t[1]-e[1],t[2]-e[2]],o=[n[0]-e[0],n[1]-e[1],n[2]-e[2]];return fe([0,0,0],[r[1]*o[2]-r[2]*o[1],r[2]*o[0]-r[0]*o[2],r[0]*o[1]-r[1]*o[0]])}const en={animations:!0,meshes:!0},tn=(e=en)=>{const n=G({},en,e);return F("partition",async e=>{const r=e.getLogger();!1!==n.meshes&&function(e,t,n){const r=new Set(e.getRoot().listBuffers().map(e=>e.getURI()));e.getRoot().listMeshes().forEach((o,s)=>{if(Array.isArray(n.meshes)&&!n.meshes.includes(o.getName()))return void t.debug(`partition: Skipping mesh #${s} with name "${o.getName()}".`);t.debug(`partition: Creating buffer for mesh "${o.getName()}".`);const i=e.createBuffer(o.getName()).setURI(nn(o.getName()||"mesh",r));o.listPrimitives().forEach(e=>{const t=e.getIndices();t&&t.setBuffer(i),e.listAttributes().forEach(e=>e.setBuffer(i)),e.listTargets().forEach(e=>{e.listAttributes().forEach(e=>e.setBuffer(i))})})})}(e,r,n),!1!==n.animations&&function(e,t,n){const r=new Set(e.getRoot().listBuffers().map(e=>e.getURI()));e.getRoot().listAnimations().forEach((o,s)=>{if(Array.isArray(n.animations)&&!n.animations.includes(o.getName()))return void t.debug(`partition: Skipping animation #${s} with name "${o.getName()}".`);t.debug(`partition: Creating buffer for animation "${o.getName()}".`);const i=e.createBuffer(o.getName()).setURI(nn(o.getName()||"animation",r));o.listSamplers().forEach(e=>{const t=e.getInput(),n=e.getOutput();t&&t.setBuffer(i),n&&n.setBuffer(i)})})}(e,r,n),n.meshes||n.animations||r.warn("partition: Select animations or meshes to create a partition."),await e.transform(Le({propertyTypes:[t.BUFFER]})),r.debug("partition: Complete.")})};function nn(e,t){let n=`${e}.bin`,r=1;for(;t.has(n);)n=`${e}_${r++}.bin`;return n}function rn(){var e=new re(4);return re!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function on(e,t){var n=an(e,t);return Math.acos(2*n*n-1)}function sn(e,t,n,r){var o,s,i,a,c,l=t[0],g=t[1],u=t[2],f=t[3],p=n[0],m=n[1],d=n[2],h=n[3];return(s=l*p+g*m+u*d+f*h)<0&&(s=-s,p=-p,m=-m,d=-d,h=-h),1-s>1e-6?(o=Math.acos(s),i=Math.sin(o),a=Math.sin((1-r)*o)/i,c=Math.sin(r*o)/i):(a=1-r,c=r),e[0]=a*l+c*p,e[1]=a*g+c*m,e[2]=a*u+c*d,e[3]=a*f+c*h,e}var an=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]};ae(),ce(1,0,0),ce(0,1,0),rn(),rn(),ie();const cn={tolerance:1e-4},ln=(e=cn)=>{const n=G({},cn,e);return F("resample",async(e,r)=>{const o=new Set,s=e.getRoot().listAccessors().length,i=e.getLogger();let a=!1;for(const t of e.getRoot().listAnimations()){const e=new Map;for(const n of t.listChannels())e.set(n.getSampler(),n.getTargetPath());for(const r of t.listSamplers())"weights"!==e.get(r)?"STEP"!==r.getInterpolation()&&"LINEAR"!==r.getInterpolation()||(o.add(r.getInput()),o.add(r.getOutput()),gn(r,e.get(r),n)):a=!0}for(const e of Array.from(o.values()))e.listParents().some(e=>!(e instanceof c))||e.dispose();e.getRoot().listAccessors().length>s&&!B(r,"resample","dedup")&&await e.transform(Ne({propertyTypes:[t.ACCESSOR]})),a&&i.warn("resample: Skipped optimizing morph target keyframes, not yet supported."),i.debug("resample: Complete.")})};function gn(e,t,n){const r=e.getInput().clone().setSparse(!1),o=e.getOutput().clone().setSparse(!1),s=n.tolerance,a=e.getInterpolation(),c=r.getCount()-1,l=[],g=[],u=[],f=[];let p=1;for(let e=1;e<c;++e){const n=r.getScalar(p-1),c=r.getScalar(e),m=r.getScalar(e+1),d=(c-n)/(m-n);let h=!1;if(c!==m&&(1!==e||c!==r.getScalar(0)))if(o.getElement(p-1,f),o.getElement(e,g),o.getElement(e+1,u),"LINEAR"===a&&"rotation"===t){const e=sn(l,f,u,d),t=on(f,g)+on(g,u);h=!i.eq(g,e,s)||t+Number.EPSILON>=Math.PI}else if("LINEAR"===a){const e=fn(l,f,u,d);h=!i.eq(g,e,s)}else"STEP"===a&&(h=!i.eq(g,f)||!i.eq(g,u));h&&(e!==p&&(r.setScalar(p,r.getScalar(e)),o.setElement(p,o.getElement(e,l))),p++)}c>0&&(r.setScalar(p,r.getScalar(c)),o.setElement(p,o.getElement(c,l)),p++),p!==r.getCount()?(r.setArray(r.getArray().slice(0,p)),o.setArray(o.getArray().slice(0,p*o.getElementSize())),e.setInput(r),e.setOutput(o)):(r.dispose(),o.dispose())}function un(e,t,n){return e*(1-n)+t*n}function fn(e,t,n,r){for(let o=0;o<t.length;o++)e[o]=un(t[o],n[o],r);return e}const pn={name:"",fps:10,pattern:/.*/,sort:!0};function mn(e=pn){const t=G({},pn,e);return F("sequence",e=>{const n=e.getLogger(),r=e.getRoot(),o=t.fps,s=r.listNodes().filter(e=>e.getName().match(t.pattern));t.sort&&s.sort((e,t)=>e.getName()>t.getName()?1:-1);const i=e.createAnimation(t.name),a=r.listBuffers()[0];s.forEach((t,n)=>{let r,c;0===n?(r=[n/o,(n+1)/o],c=[1,1,1,0,0,0]):n===s.length-1?(r=[(n-1)/o,n/o],c=[0,0,0,1,1,1]):(r=[(n-1)/o,n/o,(n+1)/o],c=[0,0,0,1,1,1,0,0,0]);const g=e.createAccessor().setArray(new Float32Array(r)).setBuffer(a),u=e.createAccessor().setArray(new Float32Array(c)).setBuffer(a).setType(y.Type.VEC3),f=e.createAnimationSampler().setInterpolation(E.Interpolation.STEP).setInput(g).setOutput(u),p=e.createAnimationChannel().setTargetNode(t).setTargetPath(l.TargetPath.SCALE).setSampler(f);i.addSampler(f).addChannel(p)}),n.debug("sequence: Complete.")})}const dn={tolerance:1e-4,overwrite:!0};function hn(e=dn){const n=G({},dn,e);if(n.tolerance>.1||n.tolerance<0)throw new Error("weld: Requires 0 ≤ tolerance ≤ 0.1");return F("weld",async(e,r)=>{const o=e.getLogger();for(const t of e.getRoot().listMeshes())for(const r of t.listPrimitives())An(e,r,n);B(r,"weld","dedup")||await e.transform(Ne({propertyTypes:[t.ACCESSOR]})),o.debug("weld: Complete.")})}function An(t,n,r){n.getIndices()&&!r.overwrite||n.getMode()!==e.Mode.POINTS&&(0===r.tolerance?function(e,t){if(t.getIndices())return;const n=t.listAttributes()[0],r=n.getCount(),o=n.getBuffer(),s=e.createAccessor().setBuffer(o).setType(y.Type.SCALAR).setArray(Z(r));t.setIndices(s)}(t,n):function(e,t,n){const r=e.getLogger(),o=t.getAttribute("POSITION"),s=t.getIndices()||e.createAccessor().setArray(Z(o.getCount())),i=new Uint32Array(new Set(s.getArray())),a=Math.max(n.tolerance,Number.EPSILON),c={};for(const e of t.listSemantics()){const n=t.getAttribute(e);c[e]=Sn(e,n,a)}var l;r.debug(`weld: Tolerance thresholds: ${l=c,Object.entries(l).map(([e,t])=>`${e}=${t}`).join(", ")}`);const g=[0,0,0],u=[0,0,0];i.sort((e,t)=>(o.getElement(e,g),o.getElement(t,u),g[0]>u[0]?1:-1));const f=Z(i.length),p=Z(i.length),m=o.getCount();let d=0,h=0;for(let e=0;e<i.length;e++){const n=i[e];for(let r=e-1;r>=0;r--){const e=f[i[r]];if(o.getElement(n,g),o.getElement(e,u),Math.abs(g[0]-u[0])>c.POSITION)break;h++;const s=t.listSemantics().every(r=>In(t.getAttribute(r),n,e,c[r])),a=t.listTargets().every(t=>t.listSemantics().every(r=>In(t.getAttribute(r),n,e,c[r])));if(s&&a){f[n]=e;break}}p[n]=f[n]===n?d++:p[f[n]]}r.debug(`weld: Iterations per vertex: ${Math.round(h/i.length)} (avg)`),r.debug(`weld: ${V(m,d)} vertices.`);const A=s.getCount(),y=Z(A,i.length);for(let e=0;e<A;e++)y[e]=p[s.getScalar(e)];t.setIndices(s.clone().setArray(y)),1===s.listParents().length&&s.dispose();for(const e of t.listAttributes())yn(t,e,p,d);for(const e of t.listTargets())for(const t of e.listAttributes())yn(e,t,p,d)}(t,n,r))}function yn(e,t,n,r){const o=(a=t.getArray(),c=r*t.getElementSize(),new(0,a.constructor)(c)),s=t.clone().setArray(o),i=new Uint8Array(r);var a,c;for(let e=0,r=[];e<n.length;e++)i[n[e]]||(s.setElement(n[e],t.getElement(e,r)),i[n[e]]=1);e.swap(t,s),1===t.listParents().length&&t.dispose()}const En=[],Tn=[];function Sn(e,t,n){return"NORMAL"===e||"TANGENT"===e?.5:e.startsWith("COLOR_")?.01:e.startsWith("TEXCOORD_")?1e-4:e.startsWith("JOINTS_")?0:e.startsWith("WEIGHTS_")?.01:(En.length=Tn.length=0,t.getMinNormalized(En),t.getMaxNormalized(Tn),n*(Math.max(...Tn)-Math.min(...En)||1))}function In(e,t,n,r,o){e.getElement(t,En),e.getElement(n,Tn);for(let t=0,n=e.getElementSize();t<n;t++)if(Math.abs(En[t]-Tn[t])>r)return!1;return!0}const Mn={ratio:.5,error:.001,lockBorder:!1},wn=n=>{const r=G({},Mn,n),o=r.simplifier;if(!o)throw new Error('simplify: simplifier dependency required — install "meshoptimizer".');return F("simplify",async(n,s)=>{const i=n.getLogger();await o.ready,await n.transform(hn({overwrite:!1}));for(const t of n.getRoot().listMeshes())for(const o of t.listPrimitives())o.getMode()===e.Mode.TRIANGLES?bn(n,o,r):i.warn(`simplify: Skipping primitive of mesh "${t.getName()}": Requires TRIANGLES draw mode.`);B(s,"simplify","dedup")||await n.transform(Ne({propertyTypes:[t.ACCESSOR]})),i.debug("simplify: Complete.")})};function bn(e,t,n){const r=G({},Mn,n),o=r.simplifier,s=e.getLogger(),i=t.getAttribute("POSITION"),a=t.getIndices(),c=i.getCount();let l=i.getArray(),g=a.getArray();if(i.getComponentType()!==y.ComponentType.FLOAT)if(i.getNormalized()){const e=l,t=new Float32Array(e.length);for(let n=0,r=i.getCount(),o=[];n<r;n++)o=i.getElement(n,o),i.setArray(t).setElement(n,o).setArray(e);l=t}else l=new Float32Array(l);a.getComponentType()!==y.ComponentType.UNSIGNED_INT&&(g=new Uint32Array(g));const u=3*Math.floor(r.ratio*c/3),[f,p]=o.simplify(g,l,3,u,r.error,r.lockBorder?["LockBorder"]:[]),[m,d]=o.compactMesh(f);s.debug(`simplify: ${V(i.getCount(),d)} vertices, error: ${p.toFixed(4)}.`);for(const e of X(t)){const n=e.clone();J(n,m,d),K(t,e,n),1===e.listParents().length&&e.dispose()}const h=a.clone();return h.setArray(c<=65534?new Uint16Array(f):f),t.setIndices(h),1===a.listParents().length&&a.dispose(),t}const Nn={ratio:1/3};function Rn(e=Nn){const t=G({},Nn,e).ratio;if(t<0||t>1)throw new Error("sparse: Ratio must be between 0 and 1.");return F("sparse",e=>{const n=e.getRoot(),r=e.getLogger();let o=0;for(const e of n.listAccessors()){const n=e.getCount(),r=Array(e.getElementSize()).fill(0),s=Array(e.getElementSize()).fill(0);let a=0;for(let o=0;o<n&&(e.getElement(o,s),i.eq(s,r,0)||a++,!(a/n>=t));o++);const c=a/n<t;c!==e.getSparse()&&(e.setSparse(c),o++)}r.debug(`sparse: Updated ${o} accessors.`),r.debug("sparse: Complete.")})}const Cn="textureResize";var On;!function(e){e.LANCZOS3="lanczos3",e.LANCZOS2="lanczos2"}(On||(On={}));const vn={size:[2048,2048],filter:On.LANCZOS3,pattern:null,slots:null};function Pn(e=vn){const t=G({},vn,e);return F(Cn,async e=>{const n=e.getLogger();for(const r of e.getRoot().listTextures()){const e=r.getName(),o=r.getURI();if(t.pattern&&!t.pattern.test(e)&&!t.pattern.test(o)){n.debug(`${Cn}: Skipping, excluded by "pattern" parameter.`);continue}if("image/png"!==r.getMimeType()&&"image/jpeg"!==r.getMimeType()){n.warn(`${Cn}: Skipping, unsupported texture type "${r.getMimeType()}".`);continue}const s=yt(r);if(t.slots&&!s.some(e=>{var n;return null==(n=t.slots)?void 0:n.test(e)})){n.debug(`${Cn}: Skipping, [${s.join(", ")}] excluded by "slots" parameter.`);continue}const[i,a]=t.size,[c,l]=r.getSize();if(c<=i&&l<=a){n.debug(`${Cn}: Skipping, not within size range.`);continue}let g=c,u=l;g>i&&(u=Math.floor(u*(i/g)),g=i),u>a&&(g=Math.floor(g*(a/u)),u=a);const f=r.getImage(),p=await S(f,r.getMimeType()),m=q(new Uint8Array(g*u*4),[g,u,4]);n.debug(`${Cn}: Resizing "${o||e}", ${p.shape} → ${m.shape}...`),n.debug(`${Cn}: Slots → [${s.join(", ")}]`);try{t.filter===On.LANCZOS3?_(p,m):k(p,m)}catch(t){if(t instanceof Error){n.warn(`${Cn}: Failed to resize "${o||e}": "${t.message}".`);continue}throw t}r.setImage(await I(m,r.getMimeType()))}n.debug(`${Cn}: Complete.`)})}const $n="textureCompress",xn=["jpeg","png","webp","avif"],zn=["image/jpeg","image/png","image/webp","image/avif"],Ln={resizeFilter:On.LANCZOS3,pattern:null,formats:null,slots:null,quality:null,effort:null,lossless:!1,nearLossless:!1},qn=function(e){const t=G({},Ln,e),n=t.targetFormat,r=t.pattern,o=t.formats,s=t.slots;if(!t.encoder)throw new Error(`${n}: encoder dependency required — install "sharp".`);return F($n,async e=>{const i=e.getLogger(),a=e.getRoot().listTextures();await Promise.all(a.map(async(a,c)=>{const l=yt(a),g=ht(a),u=a.getURI()||a.getName()||`${c+1}/${e.getRoot().listTextures().length}`,f=`${$n}(${u})`;if(!zn.includes(a.getMimeType()))return void i.debug(`${f}: Skipping, unsupported texture type "${a.getMimeType()}".`);if(r&&!r.test(a.getName())&&!r.test(a.getURI()))return void i.debug(`${f}: Skipping, excluded by "pattern" parameter.`);if(o&&!o.test(a.getMimeType()))return void i.debug(`${f}: Skipping, "${a.getMimeType()}" excluded by "formats" parameter.`);if(s&&l.length&&!l.some(e=>s.test(e)))return void i.debug(`${f}: Skipping, [${l.join(", ")}] excluded by "slots" parameter.`);if("jpeg"===t.targetFormat&&g&h.A)return void i.warn(`${f}: Skipping, [${l.join(", ")}] requires alpha channel.`);const p=kn(a);i.debug(`${f}: Format = ${p} → ${n||p}`),i.debug(`${f}: Slots = [${l.join(", ")}]`);const m=a.getImage(),d=m.byteLength;await _n(a,t);const A=a.getImage(),y=A.byteLength,E=m===A?" (SKIPPED":"";i.debug(`${f}: Size = ${j(d)} → ${j(y)}${E}`)}));const c=e.createExtension(v);a.some(e=>"image/webp"===e.getMimeType())?c.setRequired(!0):c.dispose();const l=e.createExtension(P);a.some(e=>"image/avif"===e.getMimeType())?l.setRequired(!0):l.dispose(),i.debug(`${$n}: Complete.`)})};async function _n(e,t){const n=G({},Ln,t),r=n.encoder;if(!r)throw new Error(`${n.targetFormat}: encoder dependency required — install "sharp".`);const o=kn(e),s=n.targetFormat||o,i=e.getMimeType(),c=`image/${s}`;let l={};switch(s){case"jpeg":l={quality:n.quality};break;case"png":l={quality:n.quality,effort:Gn(n.effort,100,10)};break;case"webp":l={quality:n.quality,effort:Gn(n.effort,100,6),lossless:n.lossless,nearLossless:n.nearLossless};break;case"avif":l={quality:n.quality,effort:Gn(n.effort,100,9),lossless:n.lossless}}const g=e.getImage(),u=r(g).toFormat(s,l);n.resize&&u.resize(n.resize[0],n.resize[1],{fit:"inside",kernel:n.resizeFilter,withoutEnlargement:!0});const f=a.toView(await u.toBuffer());if(!(i===c&&f.byteLength>=g.byteLength))if(i===c)e.setImage(f);else{const t=p.mimeTypeToExtension(i),n=p.mimeTypeToExtension(c),r=e.getURI().replace(new RegExp(`\\.${t}$`),`.${n}`);e.setImage(f).setMimeType(c).setURI(r)}}function kn(e){const t=e.getMimeType(),n=t.split("/").pop();if(!n||!xn.includes(n))throw new Error(`Unknown MIME type "${t}".`);return n}function Gn(e,t,n){return null==e?null:Math.round(e/t*n)}const Fn={overwrite:!1};function Bn(e=Fn){if(!e.generateTangents)throw new Error('tangents: generateTangents callback required — install "mikktspace".');const t=G({},Fn,e);return F("tangents",e=>{const n=e.getLogger(),r=new Map,o=new Map;let s=0;for(const i of e.getRoot().listMeshes()){const a=i.getName(),c=i.listPrimitives();for(let i=0;i<c.length;i++){const l=c[i];if(!Wn(l,n,a,i,t.overwrite))continue;const g=Un(l),u=l.getAttribute("POSITION").getArray(),f=l.getAttribute("NORMAL").getArray(),p=l.getAttribute(g).getArray(),m=r.get(u)||T();r.set(u,m);const d=r.get(f)||T();r.set(f,d);const h=r.get(p)||T();r.set(p,h);const A=l.getAttribute("TANGENT");A&&2===A.listParents().length&&A.dispose();const y=`${m}|${d}|${h}`;let E=o.get(y);if(E){n.debug(`tangents: Found cache for primitive ${i} of mesh "${a}".`),l.setAttribute("TANGENT",E),s++;continue}n.debug(`tangents: Generating for primitive ${i} of mesh "${a}".`);const S=l.getAttribute("POSITION").getBuffer(),I=t.generateTangents(u instanceof Float32Array?u:new Float32Array(u),f instanceof Float32Array?f:new Float32Array(f),p instanceof Float32Array?p:new Float32Array(p));for(let e=3;e<I.length;e+=4)I[e]*=-1;E=e.createAccessor().setBuffer(S).setArray(I).setType("VEC4"),l.setAttribute("TANGENT",E),o.set(y,E),s++}}s?n.debug("tangents: Complete."):n.warn("tangents: No qualifying primitives found. See debug output.")})}function Un(e){const t=e.getMaterial();if(!t)return"TEXCOORD_0";const n=t.getNormalTextureInfo();if(!n)return"TEXCOORD_0";const r=`TEXCOORD_${n.getTexCoord()}`;return e.getAttribute(r)?r:"TEXCOORD_0"}function Wn(t,n,r,o,s){return t.getMode()===e.Mode.TRIANGLES&&t.getAttribute("POSITION")&&t.getAttribute("NORMAL")&&t.getAttribute("TEXCOORD_0")?t.getAttribute("TANGENT")&&!s?(n.debug(`tangents: Skipping primitive ${o} of mesh "${r}": TANGENT found.`),!1):!t.getIndices()||(n.warn(`tangents: Skipping primitive ${o} of mesh "${r}": primitives must be unwelded.`),!1):(n.debug(`tangents: Skipping primitive ${o} of mesh "${r}": primitives must have attributes=[POSITION, NORMAL, TEXCOORD_0] and mode=TRIANGLES.`),!1)}const Hn=()=>e=>{const t=e.createExtension($).createUnlit();e.getRoot().listMaterials().forEach(e=>{e.setExtension("KHR_materials_unlit",t)})},jn={},Dn=(e=jn)=>(G({},jn,e),F("unpartition",async e=>{const t=e.getLogger(),n=e.getRoot().listBuffers()[0];e.getRoot().listAccessors().forEach(e=>e.setBuffer(n)),e.getRoot().listBuffers().forEach((e,t)=>t>0?e.dispose():null),t.debug("unpartition: Complete.")}));export{$e as DRACO_DEFAULTS,ke as FLATTEN_DEFAULTS,gt as JOIN_DEFAULTS,Ht as MESHOPT_DEFAULTS,$t as QUANTIZE_DEFAULTS,Mn as SIMPLIFY_DEFAULTS,Ln as TEXTURE_COMPRESS_DEFAULTS,vn as TEXTURE_RESIZE_DEFAULTS,On as TextureResizeFilter,dn as WELD_DEFAULTS,ee as center,ne as clearNodeParent,Ie as clearNodeTransform,we as colorspace,_n as compressTexture,St as createLayoutPlan,F as createTransform,Ne as dedup,Oe as dequantize,xe as draco,Ge as flatten,W as getGLPrimitiveCount,Fe as getNodeScene,ht as getTextureChannelMask,Be as inspect,Qe as instance,B as isTransformPending,ut as join,nt as joinPrimitives,te as listNodeScenes,dt as listTextureChannels,At as listTextureInfo,yt as listTextureSlots,jt as meshopt,Vt as metalRough,Qt as normals,tn as partition,Le as prune,xt as quantize,Tt as reorder,ln as resample,mn as sequence,wn as simplify,bn as simplifyPrimitive,It as sortPrimitiveWeights,Rn as sparse,Bn as tangents,qn as textureCompress,Pn as textureResize,Te as transformMesh,he as transformPrimitive,Hn as unlit,Dn as unpartition,Kt as unweld,hn as weld,An as weldPrimitive}; | ||
import{Primitive as t,PropertyType as e,Document as n,getBounds as r,Scene as o,PrimitiveTarget as s,MathUtils as i,BufferUtils as a,Root as c,AnimationChannel as l,Texture as g,TextureInfo as u,ExtensionProperty as f,ImageUtils as p,ComponentTypeToTypedArray as m,Material as d,TextureChannel as h,Node as A,Accessor as y,AnimationSampler as E,uuid as T}from"@gltf-transform/core";import{getPixels as S,savePixels as I}from"ndarray-pixels";import{KHRMeshQuantization as M,KHRDracoMeshCompression as w,EXTMeshGPUInstancing as b,EXTMeshoptCompression as N,KHRMaterialsIOR as R,KHRMaterialsSpecular as C,KHRMaterialsPBRSpecularGlossiness as O,EXTTextureWebP as v,EXTTextureAVIF as P,KHRMaterialsUnlit as $}from"@gltf-transform/extensions";import{read as x,KHR_DF_MODEL_ETC1S as z,KHR_DF_MODEL_UASTC as L}from"ktx-parse";import q from"ndarray";import{lanczos3 as _,lanczos2 as k}from"ndarray-lanczos";function G(){return(G=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t}).apply(this,arguments)}function F(t,e){return Object.defineProperty(e,"name",{value:t}),e}function B(t,e,n){return!!t&&t.stack.lastIndexOf(e)<t.stack.lastIndexOf(n)}async function U(t,e,n){if(!t)return null;const r=t.getImage();if(!r)return null;const o=await S(r,t.getMimeType());for(let t=0;t<o.shape[0];++t)for(let e=0;e<o.shape[1];++e)n(o,t,e);const s=await I(o,"image/png");return e.setImage(s).setMimeType("image/png")}function W(e){const n=e.getIndices(),r=e.getAttribute("POSITION");switch(e.getMode()){case t.Mode.POINTS:return r.getCount();case t.Mode.LINES:return n?n.getCount()/2:r.getCount()/2;case t.Mode.LINE_LOOP:return r.getCount();case t.Mode.LINE_STRIP:return r.getCount()-1;case t.Mode.TRIANGLES:return n?n.getCount()/3:r.getCount()/3;case t.Mode.TRIANGLE_STRIP:case t.Mode.TRIANGLE_FAN:return r.getCount()-2;default:throw new Error("Unexpected mode: "+e.getMode())}}class H{constructor(){this._map=new Map}get size(){return this._map.size}has(t){return this._map.has(t)}add(t,e){let n=this._map.get(t);return n||(n=new Set,this._map.set(t,n)),n.add(e),this}get(t){return this._map.get(t)||new Set}keys(){return this._map.keys()}}function j(t,e=2){if(0===t)return"0 Bytes";const n=e<0?0:e,r=Math.floor(Math.log(t)/Math.log(1e3));return parseFloat((t/Math.pow(1e3,r)).toFixed(n))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][r]}function D(t){return t.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function V(t,e){return`${D(t)} → ${D(e)} (${function(t,e,n=2){return(t>e?"–":"+")+(Math.abs(t-e)/t*100).toFixed(n)+"%"}(t,e)})`}function X(t){const e=[];for(const n of t.listAttributes())e.push(n);for(const n of t.listTargets())for(const t of n.listAttributes())e.push(t);return Array.from(new Set(e))}function K(t,e,n){t.swap(e,n);for(const r of t.listTargets())r.swap(e,n)}function J(t,e,n){const r=t.getElementSize(),o=t.getCount(),s=t.getArray(),i=s.slice(0,n*r);for(let t=0;t<o;t++)for(let n=0;n<r;n++)i[e[t]*r+n]=s[t*r+n];t.setArray(i)}function Z(t,e=t){const n=e<=65534?new Uint16Array(t):new Uint32Array(t);for(let t=0;t<n.length;t++)n[t]=t;return n}function Q(t){const e=n.fromGraph(t.getGraph()),r=t.getMaterial();return`${e.getRoot().listMaterials().indexOf(r)}|${t.getMode()}|${!!t.getIndices()}|${t.listSemantics().sort().map(e=>{const n=t.getAttribute(e);return`${e}:${n.getElementSize()}:${n.getComponentType()}`}).join("+")}|${t.listTargets().map(e=>e.listSemantics().sort().map(e=>{const n=t.getAttribute(e);return`${e}:${n.getElementSize()}:${n.getComponentType()}`}).join("+")).join("~")}`}const Y={pivot:"center"};function tt(t=Y){const e=G({},Y,t);return F("center",t=>{const n=t.getLogger(),o=t.getRoot(),s=o.listAnimations().length>0||o.listSkins().length>0;t.getRoot().listScenes().forEach((i,a)=>{let c;if(n.debug(`center: Scene ${a+1} / ${o.listScenes().length}.`),"string"==typeof e.pivot){const t=r(i);c=[(t.max[0]-t.min[0])/2+t.min[0],(t.max[1]-t.min[1])/2+t.min[1],(t.max[2]-t.min[2])/2+t.min[2]],"above"===e.pivot&&(c[1]=t.max[1]),"below"===e.pivot&&(c[1]=t.min[1])}else c=e.pivot;n.debug(`center: Pivot "${c.join(", ")}".`);const l=[-1*c[0],-1*c[1],-1*c[2]];if(s){n.debug("center: Model contains animation or skin. Adding a wrapper node.");const e=t.createNode("Pivot").setTranslation(l);i.listChildren().forEach(t=>e.addChild(t)),i.addChild(e)}else n.debug("center: Skipping wrapper, offsetting all root nodes."),i.listChildren().forEach(t=>{const e=t.getTranslation();t.setTranslation([e[0]+l[0],e[1]+l[1],e[2]+l[2]])})}),n.debug("center: Complete.")})}function et(t){const e=new Set;let n,r=t;for(;n=r.getParentNode();){if(e.has(n))throw new Error("Circular dependency in scene graph.");e.add(n),r=n}return r.listParents().filter(t=>t instanceof o)}function nt(t){const e=et(t),n=t.getParentNode();if(!n)return t;t.setMatrix(t.getWorldMatrix()),n.removeChild(t);for(const n of e)n.addChild(t);return t}var rt="undefined"!=typeof Float32Array?Float32Array:Array;function ot(t,e){var n=e[0],r=e[1],o=e[2],s=e[3],i=e[4],a=e[5],c=e[6],l=e[7],g=e[8],u=e[9],f=e[10],p=e[11],m=e[12],d=e[13],h=e[14],A=e[15],y=n*a-r*i,E=n*c-o*i,T=n*l-s*i,S=r*c-o*a,I=r*l-s*a,M=o*l-s*c,w=g*d-u*m,b=g*h-f*m,N=g*A-p*m,R=u*h-f*d,C=u*A-p*d,O=f*A-p*h,v=y*O-E*C+T*R+S*N-I*b+M*w;return v?(t[0]=(a*O-c*C+l*R)*(v=1/v),t[1]=(o*C-r*O-s*R)*v,t[2]=(d*M-h*I+A*S)*v,t[3]=(f*I-u*M-p*S)*v,t[4]=(c*N-i*O-l*b)*v,t[5]=(n*O-o*N+s*b)*v,t[6]=(h*T-m*M-A*E)*v,t[7]=(g*M-f*T+p*E)*v,t[8]=(i*C-a*N+l*w)*v,t[9]=(r*N-n*C-s*w)*v,t[10]=(m*I-d*T+A*y)*v,t[11]=(u*T-g*I-p*y)*v,t[12]=(a*b-i*R-c*w)*v,t[13]=(n*R-r*b+o*w)*v,t[14]=(d*E-m*S-h*y)*v,t[15]=(g*S-u*E+f*y)*v,t):null}function st(t,e,n){var r=e[0],o=e[1],s=e[2],i=e[3],a=e[4],c=e[5],l=e[6],g=e[7],u=e[8],f=e[9],p=e[10],m=e[11],d=e[12],h=e[13],A=e[14],y=e[15],E=n[0],T=n[1],S=n[2],I=n[3];return t[0]=E*r+T*a+S*u+I*d,t[1]=E*o+T*c+S*f+I*h,t[2]=E*s+T*l+S*p+I*A,t[3]=E*i+T*g+S*m+I*y,t[4]=(E=n[4])*r+(T=n[5])*a+(S=n[6])*u+(I=n[7])*d,t[5]=E*o+T*c+S*f+I*h,t[6]=E*s+T*l+S*p+I*A,t[7]=E*i+T*g+S*m+I*y,t[8]=(E=n[8])*r+(T=n[9])*a+(S=n[10])*u+(I=n[11])*d,t[9]=E*o+T*c+S*f+I*h,t[10]=E*s+T*l+S*p+I*A,t[11]=E*i+T*g+S*m+I*y,t[12]=(E=n[12])*r+(T=n[13])*a+(S=n[14])*u+(I=n[15])*d,t[13]=E*o+T*c+S*f+I*h,t[14]=E*s+T*l+S*p+I*A,t[15]=E*i+T*g+S*m+I*y,t}function it(){var t=new rt(9);return rt!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function at(){var t=new rt(3);return rt!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function ct(t,e,n){var r=new rt(3);return r[0]=t,r[1]=e,r[2]=n,r}function lt(t,e,n){return t[0]=Math.min(e[0],n[0]),t[1]=Math.min(e[1],n[1]),t[2]=Math.min(e[2],n[2]),t}function gt(t,e,n){return t[0]=Math.max(e[0],n[0]),t[1]=Math.max(e[1],n[1]),t[2]=Math.max(e[2],n[2]),t}function ut(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t}function ft(t,e){var n=e[0],r=e[1],o=e[2],s=n*n+r*r+o*o;return s>0&&(s=1/Math.sqrt(s)),t[0]=e[0]*s,t[1]=e[1]*s,t[2]=e[2]*s,t}function pt(t,e,n){var r=e[0],o=e[1],s=e[2],i=n[3]*r+n[7]*o+n[11]*s+n[15];return t[0]=(n[0]*r+n[4]*o+n[8]*s+n[12])/(i=i||1),t[1]=(n[1]*r+n[5]*o+n[9]*s+n[13])/i,t[2]=(n[2]*r+n[6]*o+n[10]*s+n[14])/i,t}function mt(t,e,n){var r=e[0],o=e[1],s=e[2];return t[0]=r*n[0]+o*n[3]+s*n[6],t[1]=r*n[1]+o*n[4]+s*n[7],t[2]=r*n[2]+o*n[5]+s*n[8],t}function dt(){var t=new rt(4);return rt!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function ht(t,e,n=new Set){var r;const o=t.getAttribute("POSITION"),s=(null==(r=t.getIndices())?void 0:r.getArray())||Z(o.getCount());o&&At(e,o,s,new Set(n));const i=t.getAttribute("NORMAL");i&&yt(e,i,s,new Set(n));const a=t.getAttribute("TANGENT");a&&Et(e,a,s,new Set(n));for(const r of t.listTargets()){const t=r.getAttribute("POSITION");t&&At(e,t,s,new Set(n));const o=r.getAttribute("NORMAL");o&&yt(e,o,s,new Set(n));const i=r.getAttribute("TANGENT");i&&Et(e,i,s,new Set(n))}for(let t=0;t<s.length;t++)n.add(s[t])}function At(t,e,n,r){const o=new Float32Array(3*e.getCount()),s=e.getElementSize();for(let t=0,n=[],r=e.getCount();t<r;t++)o.set(e.getElement(t,n),t*s);const i=at();for(let s=0;s<n.length;s++){const a=n[s];r.has(a)||(e.getElement(a,i),pt(i,i,t),o.set(i,3*a),r.add(a))}e.setArray(o).setNormalized(!1)}function yt(t,e,n,r){const o=it();var s,i;(s=o)[0]=(i=t)[0],s[1]=i[1],s[2]=i[2],s[3]=i[4],s[4]=i[5],s[5]=i[6],s[6]=i[8],s[7]=i[9],s[8]=i[10],function(t,e){var n=e[0],r=e[1],o=e[2],s=e[3],i=e[4],a=e[5],c=e[6],l=e[7],g=e[8],u=g*i-a*l,f=-g*s+a*c,p=l*s-i*c,m=n*u+r*f+o*p;m&&(t[0]=u*(m=1/m),t[1]=(-g*r+o*l)*m,t[2]=(a*r-o*i)*m,t[3]=f*m,t[4]=(g*n-o*c)*m,t[5]=(-a*n+o*s)*m,t[6]=p*m,t[7]=(-l*n+r*c)*m,t[8]=(i*n-r*s)*m)}(o,o),function(t,e){if(t===e){var n=e[1],r=e[2],o=e[5];t[1]=e[3],t[2]=e[6],t[3]=n,t[5]=e[7],t[6]=r,t[7]=o}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8]}(o,o);const a=at();for(let t=0;t<n.length;t++){const s=n[t];r.has(s)||(e.getElement(s,a),mt(a,a,o),ft(a,a),e.setElement(s,a),r.add(s))}}function Et(t,e,n,r){const o=at(),s=dt();for(let i=0;i<n.length;i++){const a=n[i];if(r.has(a))continue;e.getElement(a,s);const[c,l,g]=s;o[0]=t[0]*c+t[4]*l+t[8]*g,o[1]=t[1]*c+t[5]*l+t[9]*g,o[2]=t[2]*c+t[6]*l+t[10]*g,ft(o,o),s[0]=o[0],s[1]=o[1],s[2]=o[2],e.setElement(a,s),r.add(a)}}function Tt(n,r,o=!1,i){for(const t of n.listPrimitives())if(t.listParents().some(t=>t.propertyType===e.MESH&&t!==n)){const e=t.clone();n.swap(t,e);for(const t of e.listTargets()){const n=t.clone();e.swap(t,n)}}if(!o){const e=new Set([...n.listPrimitives(),...n.listPrimitives().flatMap(t=>t.listTargets())]),r=new Map;for(const o of n.listPrimitives())for(const n of X(o))n.listParents().some(n=>(n instanceof t||n instanceof s)&&!e.has(n))&&!r.has(n)&&r.set(n,n.clone());for(const t of e)for(const[e,n]of r)t.swap(e,n)}i=i||new Set;for(const t of n.listPrimitives())ht(t,r,i)}Math.hypot||(Math.hypot=function(){for(var t=0,e=arguments.length;e--;)t+=arguments[e]*arguments[e];return Math.sqrt(t)}),at(),dt();const St=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];function It(t){const e=t.getMesh(),n=t.getMatrix();e&&!i.eq(n,St)&&Tt(e,n);for(const e of t.listChildren()){const t=e.getMatrix();st(t,t,n),e.setMatrix(t)}return t.setMatrix(St)}const Mt="colorspace";function wt(t){return F(Mt,e=>{const n=e.getLogger();if("linear"===t.inputEncoding)return void n.info(`${Mt}: Vertex colors already linear. Skipping conversion.`);if("sRGB"!==t.inputEncoding)return void n.error(`${Mt}: Unknown input encoding "${t.inputEncoding}" – should be "sRGB" or "linear". Skipping conversion.`);const r=new Set;function o(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function s(t){const e=[0,0,0];let n;for(let s=0;n=t.getAttribute(`COLOR_${s}`);s++)if(!r.has(n)){for(let t=0;t<n.getCount();t++)n.getElement(t,e),e[0]=o(e[0]),e[1]=o(e[1]),e[2]=o(e[2]),n.setElement(t,e);r.add(n)}}e.getRoot().listMeshes().forEach(t=>t.listPrimitives().forEach(s)),n.debug(`${Mt}: Complete.`)})}const bt={propertyTypes:[e.ACCESSOR,e.MESH,e.TEXTURE,e.MATERIAL]},Nt=function(t=bt){const n=G({},bt,t),r=new Set(n.propertyTypes);for(const t of n.propertyTypes)if(!bt.propertyTypes.includes(t))throw new Error(`dedup: Unsupported deduplication on type "${t}".`);return F("dedup",t=>{const n=t.getLogger();r.has(e.ACCESSOR)&&function(t,e){const n=new Set,r=new Set,o=new Set,s=new Set,i=e.getRoot().listMeshes();i.forEach(t=>{t.listPrimitives().forEach(t=>{t.listAttributes().forEach(t=>r.add(t));const e=t.getIndices();e&&n.add(e)})});for(const t of e.getRoot().listAnimations())for(const e of t.listSamplers()){const t=e.getInput(),n=e.getOutput();t&&o.add(t),n&&s.add(n)}function c(t){const e=new Map;for(let n=0;n<t.length;n++){const r=t[n],o=a.toView(r.getArray());if(!e.has(r))for(let n=0;n<t.length;n++){const s=t[n];r!==s&&(e.has(s)||r.getType()===s.getType()&&r.getComponentType()===s.getComponentType()&&r.getCount()===s.getCount()&&r.getNormalized()===s.getNormalized()&&a.equals(o,a.toView(s.getArray()))&&e.set(s,r))}}return e}const l=c(Array.from(n));t.debug(`dedup: Found ${l.size} duplicates among ${n.size} indices.`);const g=c(Array.from(r));t.debug(`dedup: Found ${g.size} duplicates among ${r.size} attributes.`);const u=c(Array.from(o)),f=c(Array.from(s));t.debug(`dedup: Found ${u.size+f.size} duplicates among ${o.size+s.size} animation accessors.`),i.forEach(t=>{t.listPrimitives().forEach(t=>{t.listAttributes().forEach(e=>{g.has(e)&&t.swap(e,g.get(e))});const e=t.getIndices();e&&l.has(e)&&t.swap(e,l.get(e))})}),Array.from(l.keys()).forEach(t=>t.dispose()),Array.from(g.keys()).forEach(t=>t.dispose());for(const t of e.getRoot().listAnimations())for(const e of t.listSamplers()){const t=e.getInput(),n=e.getOutput();t&&u.has(t)&&e.swap(t,u.get(t)),n&&f.has(n)&&e.swap(n,f.get(n))}Array.from(u.keys()).forEach(t=>t.dispose()),Array.from(f.keys()).forEach(t=>t.dispose())}(n,t),r.has(e.TEXTURE)&&function(t,e){const n=e.getRoot(),r=n.listTextures(),o=new Map;for(let t=0;t<r.length;t++){const e=r[t],n=e.getImage();if(!o.has(e))for(let t=0;t<r.length;t++){const s=r[t],i=s.getImage();if(e===s)continue;if(o.has(s))continue;if(e.getMimeType()!==s.getMimeType())continue;const c=e.getSize(),l=s.getSize();c&&l&&c[0]===l[0]&&c[1]===l[1]&&n&&i&&a.equals(n,i)&&o.set(s,e)}}t.debug(`dedup: Found ${o.size} duplicates among ${n.listTextures().length} textures.`),Array.from(o.entries()).forEach(([t,e])=>{t.listParents().forEach(n=>{n instanceof c||n.swap(t,e)}),t.dispose()})}(n,t),r.has(e.MATERIAL)&&function(t,e){const n=e.getRoot(),r=n.listMaterials(),o=new Map,s=new Set(["name"]);for(let t=0;t<r.length;t++){const e=r[t];if(!o.has(e))for(let t=0;t<r.length;t++){const n=r[t];e!==n&&(o.has(n)||e.equals(n,s)&&o.set(n,e))}}t.debug(`dedup: Found ${o.size} duplicates among ${n.listMaterials().length} materials.`),Array.from(o.entries()).forEach(([t,e])=>{t.listParents().forEach(n=>{n instanceof c||n.swap(t,e)}),t.dispose()})}(n,t),r.has(e.MESH)&&function(t,n){const r=n.getRoot(),o=new Map;r.listAccessors().forEach((t,e)=>o.set(t,e)),r.listMaterials().forEach((t,e)=>o.set(t,e));const s=r.listMeshes().length,i=new Map;for(const t of r.listMeshes()){const n=[];for(const e of t.listPrimitives())n.push(Rt(e,o));const r=n.join(";");if(i.has(r)){const n=i.get(r);t.listParents().forEach(r=>{r.propertyType!==e.ROOT&&r.swap(t,n)}),t.dispose()}else i.set(r,t)}t.debug(`dedup: Found ${s-i.size} duplicates among ${s} meshes.`)}(n,t),n.debug("dedup: Complete.")})};function Rt(e,n){const r=[];for(const t of e.listSemantics()){const o=e.getAttribute(t);r.push(t+":"+n.get(o))}if(e instanceof t){const t=e.getIndices();t&&r.push("indices:"+n.get(t));const o=e.getMaterial();o&&r.push("material:"+n.get(o)),r.push("mode:"+e.getMode());for(const t of e.listTargets())r.push("target:"+Rt(t,n))}return r.join(",")}const Ct={pattern:/^((?!JOINTS_).)*$/};function Ot(t=Ct){const e=G({},Ct,t);return F("dequantize",t=>{const n=t.getLogger();for(const n of t.getRoot().listMeshes())for(const t of n.listPrimitives())vt(t,e);t.createExtension(M).dispose(),n.debug("dequantize: Complete.")})}function vt(t,e){for(const n of t.listSemantics())Pt(n,t.getAttribute(n),e);for(const n of t.listTargets())for(const t of n.listSemantics())Pt(t,n.getAttribute(t),e)}function Pt(t,e,n){if(!e.getArray())return;if(!n.pattern.test(t))return;if(e.getComponentSize()>=4)return;const r=e.getArray(),o=new Float32Array(r.length);for(let t=0,n=e.getCount(),s=[];t<n;t++)s=e.getElement(t,s),e.setArray(o).setElement(t,s).setArray(r);e.setArray(o).setNormalized(!1)}const $t={method:"edgebreaker",encodeSpeed:5,decodeSpeed:5,quantizePosition:14,quantizeNormal:10,quantizeColor:8,quantizeTexcoord:12,quantizeGeneric:12,quantizationVolume:"mesh"},xt=(t=$t)=>{const e=G({},$t,t);return F("draco",t=>{t.createExtension(w).setRequired(!0).setEncoderOptions({method:"edgebreaker"===e.method?w.EncoderMethod.EDGEBREAKER:w.EncoderMethod.SEQUENTIAL,encodeSpeed:e.encodeSpeed,decodeSpeed:e.decodeSpeed,quantizationBits:{POSITION:e.quantizePosition,NORMAL:e.quantizeNormal,COLOR:e.quantizeColor,TEX_COORD:e.quantizeTexcoord,GENERIC:e.quantizeGeneric},quantizationVolume:e.quantizationVolume})})},zt={propertyTypes:[e.NODE,e.SKIN,e.MESH,e.CAMERA,e.PRIMITIVE,e.PRIMITIVE_TARGET,e.ANIMATION,e.MATERIAL,e.TEXTURE,e.ACCESSOR,e.BUFFER],keepLeaves:!1,keepAttributes:!0},Lt=function(t=zt){const n=G({},zt,t),r=new Set(n.propertyTypes);return F("prune",t=>{const s=t.getLogger(),i=t.getRoot(),a=t.getGraph(),g={};if(r.has(e.MESH))for(const t of i.listMeshes())t.listPrimitives().length>0||(t.dispose(),m(t));if(r.has(e.NODE)&&!n.keepLeaves&&i.listScenes().forEach(function t(n){if(n.listChildren().forEach(t),n instanceof o)return;const r=a.listParentEdges(n).some(t=>{const n=t.getParent().propertyType;return n!==e.ROOT&&n!==e.SCENE&&n!==e.NODE});0!==a.listChildren(n).length||r||(n.dispose(),m(n))}),r.has(e.NODE)&&i.listNodes().forEach(u),r.has(e.SKIN)&&i.listSkins().forEach(u),r.has(e.MESH)&&i.listMeshes().forEach(u),r.has(e.CAMERA)&&i.listCameras().forEach(u),r.has(e.PRIMITIVE)&&f(a,e.PRIMITIVE),r.has(e.PRIMITIVE_TARGET)&&f(a,e.PRIMITIVE_TARGET),!n.keepAttributes&&r.has(e.ACCESSOR))for(const e of i.listMeshes())for(const n of e.listPrimitives()){const e=_t(t,n.getMaterial()),r=qt(n,e);p(n,r),n.listTargets().forEach(t=>p(t,r))}if(r.has(e.ANIMATION))for(const t of i.listAnimations()){for(const e of t.listChannels())e.getTargetNode()||(e.dispose(),m(e));if(t.listChannels().length)t.listSamplers().forEach(u);else{const e=t.listSamplers();u(t),e.forEach(u)}}if(r.has(e.MATERIAL)&&i.listMaterials().forEach(u),r.has(e.TEXTURE)&&i.listTextures().forEach(u),r.has(e.ACCESSOR)&&i.listAccessors().forEach(u),r.has(e.BUFFER)&&i.listBuffers().forEach(u),Object.keys(g).length){const t=Object.keys(g).map(t=>`${t} (${g[t]})`).join(", ");s.info(`prune: Removed types... ${t}`)}else s.info("prune: No unused properties found.");function u(t){t.listParents().filter(t=>!(t instanceof c||t instanceof l)).length||(t.dispose(),m(t))}function f(t,e){t.listEdges().map(t=>t.getParent()).filter(t=>t.propertyType===e).forEach(u)}function p(t,e){for(const n of e)t.setAttribute(n,null)}function m(t){g[t.propertyType]=g[t.propertyType]||0,g[t.propertyType]++}s.debug("prune: Complete.")})};function qt(t,e){const n=[];for(const r of t.listSemantics())"TANGENT"!==r||e.has(r)?(r.startsWith("TEXCOORD_")&&!e.has(r)||r.startsWith("COLOR_")&&"COLOR_0"!==r)&&n.push(r):n.push(r);return n}function _t(t,e,n=new Set){if(!e)return n;const r=t.getGraph().listChildEdges(e),o=new Set;for(const t of r)t.getChild()instanceof g&&o.add(t.getName());for(const e of r){const r=e.getName(),s=e.getChild();s instanceof u&&o.has(r.replace(/Info$/,""))&&n.add(`TEXCOORD_${s.getTexCoord()}`),s instanceof g&&r.match(/normalTexture/i)&&n.add("TANGENT"),s instanceof f&&_t(t,s,n)}return n}const kt={};function Gt(t=kt){return G({},kt,t),F("flatten",async t=>{const n=t.getRoot(),r=t.getLogger(),o=new Set;for(const t of n.listSkins())for(const e of t.listJoints())o.add(e);const s=new Set;for(const t of n.listAnimations())for(const e of t.listChannels()){const t=e.getTargetNode();t&&s.add(t)}const i=new Set,a=new Set;for(const t of n.listScenes())t.traverse(t=>{const e=t.getParentNode();e&&((o.has(e)||i.has(e))&&i.add(t),(s.has(e)||a.has(e))&&a.add(t))});for(const t of n.listScenes())t.traverse(t=>{s.has(t)||i.has(t)||a.has(t)||nt(t)});s.size&&r.debug("flatten: Flattening node hierarchies with TRS animation not yet supported."),await t.transform(Lt({propertyTypes:[e.NODE],keepLeaves:!1})),r.debug("flatten: Complete.")})}function Ft(t){return et(t)[0]||null}function Bt(t){return{scenes:Ut(t),meshes:Wt(t),materials:Ht(t),textures:jt(t),animations:Dt(t)}}function Ut(t){return{properties:t.getRoot().listScenes().map(t=>{const e=t.listChildren()[0],n=r(t);return{name:t.getName(),rootName:e?e.getName():"",bboxMin:Kt(n.min),bboxMax:Kt(n.max)}})}}function Wt(t){return{properties:t.getRoot().listMeshes().map(t=>{const n=t.listParents().filter(t=>t.propertyType!==e.ROOT).length;let r=0,o=0;const s=new Set,i=new Set,a=new Set;t.listPrimitives().forEach(t=>{for(const e of t.listSemantics()){const n=t.getAttribute(e);s.add(e+":"+Jt(n)),a.add(n)}for(const e of t.listTargets())e.listAttributes().forEach(t=>a.add(t));const e=t.getIndices();e&&(i.add(Jt(e)),a.add(e)),o+=t.listAttributes()[0].getCount(),r+=W(t)});let c=0;Array.from(a).forEach(t=>c+=t.getArray().byteLength);const l=t.listPrimitives().map(t=>Vt[t.getMode()]);return{name:t.getName(),mode:Array.from(new Set(l)),primitives:t.listPrimitives().length,glPrimitives:r,vertices:o,indices:Array.from(i).sort(),attributes:Array.from(s).sort(),instances:n,size:c}})}}function Ht(t){return{properties:t.getRoot().listMaterials().map(n=>{const r=n.listParents().filter(t=>t.propertyType!==e.ROOT).length,o=new Set(n.listExtensions()),s=t.getGraph().listEdges().filter(t=>{const e=t.getChild(),r=t.getParent();return e instanceof g&&r===n||!!(e instanceof g&&r instanceof f&&o.has(r))}).map(t=>t.getName());return{name:n.getName(),instances:r,textures:s,alphaMode:n.getAlphaMode(),doubleSided:n.getDoubleSided()}})}}function jt(t){return{properties:t.getRoot().listTextures().map(n=>{const r=n.listParents().filter(t=>t.propertyType!==e.ROOT).length,o=t.getGraph().listParentEdges(n).filter(t=>t.getParent().propertyType!==e.ROOT).map(t=>t.getName()),s=p.getSize(n.getImage(),n.getMimeType());let i="";if("image/ktx2"===n.getMimeType()){const t=x(n.getImage()).dataFormatDescriptor[0];t.colorModel===z?i="ETC1S":t.colorModel===L&&(i="UASTC")}return{name:n.getName(),uri:n.getURI(),slots:Array.from(new Set(o)),instances:r,mimeType:n.getMimeType(),compression:i,resolution:s?s.join("x"):"",size:n.getImage().byteLength,gpuSize:p.getVRAMByteLength(n.getImage(),n.getMimeType())}})}}function Dt(t){return{properties:t.getRoot().listAnimations().map(t=>{let e=Infinity,n=-Infinity;t.listSamplers().forEach(t=>{const r=t.getInput();r&&(e=Math.min(e,r.getMin([])[0]),n=Math.max(n,r.getMax([])[0]))});let r=0,o=0;const s=new Set;return t.listSamplers().forEach(t=>{const e=t.getInput(),n=t.getOutput();e&&(o+=e.getCount(),s.add(e),n&&s.add(n))}),Array.from(s).forEach(t=>{r+=t.getArray().byteLength}),{name:t.getName(),channels:t.listChannels().length,samplers:t.listSamplers().length,duration:Math.round(1e3*(n-e))/1e3,keyframes:o,size:r}})}}const Vt=["POINTS","LINES","LINE_LOOP","LINE_STRIP","TRIANGLES","TRIANGLE_STRIP","TRIANGLE_FAN"],Xt={Float32Array:"f32",Uint32Array:"u32",Uint16Array:"u16",Uint8Array:"u8",Int32Array:"i32",Int16Array:"i16",Int8Array:"i8"};function Kt(t){for(let e=0;e<t.length;e++)t[e].toFixed&&(t[e]=Number(t[e].toFixed(5)));return t}function Jt(t){const e=t.getArray();return(Xt[e.constructor.name]||"?")+(t.getNormalized()?"_norm":"")}const Zt={min:2};function Qt(t=Zt){const e=G({},Zt,t);return F("instance",t=>{const n=t.getLogger(),r=t.getRoot(),o=t.createExtension(b);if(r.listAnimations().length)return n.warn("instance: Instancing is not currently supported for animated models."),void n.debug("instance: Complete.");let s=0,a=0;for(const c of r.listScenes()){const r=new Map;c.traverse(t=>{const e=t.getMesh();e&&r.set(e,(r.get(e)||new Set).add(t))});const l=[];for(const g of Array.from(r.keys())){const u=Array.from(r.get(g));if(u.length<e.min)continue;if(u.some(t=>t.getSkin()))continue;const f=te(t,o,g,u.length),p=f.getAttribute("TRANSLATION"),m=f.getAttribute("ROTATION"),d=f.getAttribute("SCALE"),h=t.createNode().setMesh(g).setExtension("EXT_mesh_gpu_instancing",f);c.addChild(h);let A=!1,y=!1,E=!1;for(let t=0;t<u.length;t++){let e,n,r;const o=u[t];p.setElement(t,e=o.getWorldTranslation()),m.setElement(t,n=o.getWorldRotation()),d.setElement(t,r=o.getWorldScale()),i.eq(e,[0,0,0])||(A=!0),i.eq(n,[0,0,0,1])||(y=!0),i.eq(r,[1,1,1])||(E=!0),o.setMesh(null),l.push(o)}A||p.dispose(),y||m.dispose(),E||d.dispose(),Yt(l,n),s++,a+=u.length}}n.info(s>0?`instance: Created ${s} batches, with ${a} total instances.`:`instance: No meshes with ≥${e.min} parent nodes were found.`),0===o.listProperties().length&&o.dispose(),n.debug("instance: Complete.")})}function Yt(t,e){let n,r=0;for(;n=t.pop();){if(n.listChildren().length||n.getCamera()||n.getMesh()||n.getSkin()||n.listExtensions().length)continue;const e=n.getParentNode();e&&t.push(e),n.dispose(),r++}e.debug(`instance: Removed ${r} unused nodes.`)}function te(t,e,n,r){const o=n.listPrimitives()[0].getAttribute("POSITION").getBuffer(),s=t.createAccessor().setType("VEC3").setArray(new Float32Array(3*r)).setBuffer(o),i=t.createAccessor().setType("VEC4").setArray(new Float32Array(4*r)).setBuffer(o),a=t.createAccessor().setType("VEC3").setArray(new Float32Array(3*r)).setBuffer(o);return e.createInstancedMesh().setAttribute("TRANSLATION",s).setAttribute("ROTATION",i).setAttribute("SCALE",a)}const ee={skipValidation:!1};function ne(t,e={}){e=G({},ee,e);const r=t[0],o=n.fromGraph(r.getGraph());if(!e.skipValidation&&new Set(t.map(Q)).size>1)throw new Error("Requires ≥2 Primitives, sharing the same Material and Mode, with compatible vertex attributes and indices.");const s=[],i=[];let a=0,c=0;for(const e of t){const t=re(e),n=[];for(let e=0;e<t.length;e++){const r=t[e];void 0===n[r]&&(n[r]=a++),c++}s.push(new Uint32Array(n)),i.push(t)}const l=o.createPrimitive().setMode(r.getMode()).setMaterial(r.getMaterial());for(const t of r.listSemantics()){const e=r.getAttribute(t),n=m[e.getComponentType()],s=o.createAccessor().setType(e.getType()).setBuffer(e.getBuffer()).setNormalized(e.getNormalized()).setArray(new n(a*e.getElementSize()));l.setAttribute(t,s)}const g=(r.getIndices()?Z(a):null)&&o.createAccessor().setBuffer(r.getIndices().getBuffer()).setArray(Z(c,a));l.setIndices(g);let u=0;for(let e=0;e<s.length;e++){const n=t[e],r=s[e],o=i[e],a=u;let c=a;for(const t of l.listSemantics()){const e=n.getAttribute(t),s=l.getAttribute(t),i=[];c=a;for(let t=0;t<o.length;t++){const n=o[t];e.getElement(n,i),s.setElement(r[n],i),g&&g.setScalar(c++,r[n])}}u=c}return l}function re(t){const e=t.getIndices();return e?e.getArray():Z(t.getAttribute("POSITION").getCount())}const{ROOT:oe,NODE:se,MESH:ie,PRIMITIVE:ae,ACCESSOR:ce}=e,le=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],ge={keepMeshes:!1,keepNamed:!1};function ue(t=ge){const e=G({},ge,t);return F("join",async t=>{const n=t.getRoot(),r=t.getLogger();for(const r of n.listScenes())fe(t,r,e),r.traverse(n=>fe(t,n,e));await t.transform(Lt({propertyTypes:[se,ie,ae,ce],keepLeaves:!1,keepAttributes:!0})),r.debug("join: Complete.")})}function fe(t,n,r){const o=t.getLogger(),s={},i=n.listChildren();for(let t=0;t<i.length;t++){const e=i[t];if(e.listParents().some(t=>t instanceof l))continue;const n=e.getMesh();if(n&&!e.getExtension("EXT_mesh_gpu_instancing")&&!e.getSkin())for(const o of n.listPrimitives()){if(o.listTargets().length>0)continue;const i=o.getMaterial();if(i&&i.getExtension("KHR_materials_volume"))continue;let a=Q(o);const c=n.getName()||e.getName();(r.keepMeshes||r.keepNamed&&c)&&(a+=`|${t}`),a in s||(s[a]={prims:[],primMeshes:[],primNodes:[],dstNode:e,dstMesh:void 0});const l=s[a];l.prims.push(o),l.primNodes.push(e)}}const a=Object.values(s).filter(({prims:t})=>t.length>1),c=new Set(a.flatMap(t=>t.primNodes));for(const t of c){const e=t.getMesh();e.listParents().some(e=>e.propertyType!==oe&&t!==e)&&t.setMesh(e.clone())}for(const t of a){const{dstNode:e,primNodes:n}=t;t.dstMesh=e.getMesh(),t.primMeshes=n.map(t=>t.getMesh())}for(const t of a){const{prims:n,primNodes:r,primMeshes:s,dstNode:i,dstMesh:a}=t,c=i.getMatrix();for(let t=0;t<n.length;t++){const o=r[t];let a=n[t];s[t].removePrimitive(a),(a.listParents().some(t=>t.propertyType!==e.ROOT)||me(a))&&(a=n[t]=pe(n[t])),o!==i&&(st(le,ot(le,c),o.getMatrix()),ht(a,le))}const l=ne(n),g=l.listAttributes()[0].getCount();a.addPrimitive(l),o.debug(`join: Joined Primitives (${n.length}) containing ${D(g)} vertices under Node "${i.getName()}".`)}}function pe(t){const e=t.clone();for(const t of e.listSemantics())e.setAttribute(t,e.getAttribute(t).clone());const n=e.getIndices();return n&&e.setIndices(n.clone()),e}function me(t){for(const e of t.listAttributes())for(const n of e.listParents())if(n!==t&&n.propertyType!==oe)return!0;return!1}function de(t){const e=he(t),n=[];return e&h.R&&n.push(h.R),e&h.G&&n.push(h.G),e&h.B&&n.push(h.B),e&h.A&&n.push(h.A),n}function he(t){const r=n.fromGraph(t.getGraph());let o=0;for(const n of r.getGraph().listParentEdges(t)){const t=n.getParent();let{channels:s}=n.getAttributes();s&&"baseColorTexture"===n.getName()&&t instanceof d&&t.getAlphaMode()===d.AlphaMode.OPAQUE&&(s&=~h.A),s?o|=s:t.propertyType!==e.ROOT&&r.getLogger().warn(`Missing attribute ".channels" on edge, "${n.getName()}".`)}return o}function Ae(t){const e=t.getGraph(),n=[];for(const r of e.listParentEdges(t)){const t=r.getParent(),o=r.getName()+"Info";for(const r of e.listChildEdges(t)){const t=r.getChild();t instanceof u&&r.getName()===o&&n.push(t)}}return n}function ye(t){const e=n.fromGraph(t.getGraph()).getRoot(),r=t.getGraph().listParentEdges(t).filter(t=>t.getParent()!==e).map(t=>t.getName());return Array.from(new Set(r))}const Ee={target:"size"};function Te(n){const r=G({},Ee,n),o=r.encoder;if(!o)throw new Error('reorder: encoder dependency required — install "meshoptimizer".');return F("reorder",async n=>{const s=n.getLogger();await o.ready;const i=Se(n);for(const e of i.indicesToAttributes.keys()){const n=e.clone();let s=n.getArray().slice();s instanceof Uint32Array||(s=new Uint32Array(s));const[a,c]=o.reorderMesh(s,i.indicesToMode.get(e)===t.Mode.TRIANGLES,"size"===r.target);n.setArray(c<=65534?new Uint16Array(s):s);for(const t of i.indicesToAttributes.get(e)){const r=t.clone();J(r,a,c);for(const o of i.attributesToPrimitives.get(t))if(o.getIndices()===e&&o.swap(e,n),o.getIndices()===n){o.swap(t,r);for(const e of o.listTargets())e.swap(t,r)}}}await n.transform(Lt({propertyTypes:[e.ACCESSOR]})),i.indicesToAttributes.size?s.debug("reorder: Complete."):s.warn("reorder: No qualifying primitives found; may need to weld first.")})}function Se(t){const e=new H,n=new Map,r=new H;for(const o of t.getRoot().listMeshes())for(const t of o.listPrimitives()){const o=t.getIndices();if(o){n.set(o,t.getMode());for(const n of X(t))e.add(o,n),r.add(n,t)}}return{indicesToAttributes:e,indicesToMode:n,attributesToPrimitives:r}}function Ie(t,e=Infinity){if(Number.isFinite(e)&&e%4||e<=0)throw new Error("Limit must be positive multiple of four.");const n=t.getAttribute("POSITION").getCount(),r=t.listSemantics().filter(t=>t.startsWith("WEIGHTS_")).length,o=new Uint16Array(4*r),s=new Float32Array(4*r),a=new Float32Array(4*r),c=new Uint32Array(4*r),l=new Uint32Array(4*r);for(let e=0;e<n;e++){Me(t,e,"WEIGHTS",s),Me(t,e,"JOINTS",c);for(let t=0;t<4*r;t++)o[t]=t;o.sort((t,e)=>s[t]>s[e]?-1:1);for(let t=0;t<o.length;t++)a[t]=s[o[t]],l[t]=c[o[t]];we(t,e,"WEIGHTS",a),we(t,e,"JOINTS",l)}for(let n=r;4*n>e;n--){const e=t.getAttribute("WEIGHTS_"+(n-1)),r=t.getAttribute("JOINTS_"+(n-1));t.setAttribute("WEIGHTS_"+(n-1),null),t.setAttribute("JOINTS_"+(n-1),null),1===e.listParents().length&&e.dispose(),1===r.listParents().length&&r.dispose()}!function(t){if(!function(t){const e=t.listSemantics().filter(t=>t.startsWith("WEIGHTS_")).map(e=>t.getAttribute(e)),n=e.map(t=>t.getNormalized()),r=e.map(t=>t.getComponentType());return 1===new Set(n).size&&1===new Set(r).size}(t))return;const e=t.getAttribute("POSITION").getCount(),n=t.listSemantics().filter(t=>t.startsWith("WEIGHTS_")).length,r=t.getAttribute("WEIGHTS_0"),o=r.getArray(),s=r.getComponentType(),a=r.getNormalized(),c=a?s:void 0,l=a?i.decodeNormalizedInt(1,s):Number.EPSILON,g=new Uint32Array(4*n).fill(0),u=o.slice(0,4*n).fill(0);for(let n=0;n<e;n++){Me(t,n,"JOINTS",g),Me(t,n,"WEIGHTS",u,c);let e=be(u,c);if(0!==e){if(Math.abs(1-e)>l)for(let t=0;t<u.length;t++)if(a){const n=i.encodeNormalizedInt(u[t]/e,s);u[t]=i.decodeNormalizedInt(n,s)}else u[t]/=e;if(e=be(u,c),a&&1!==e)for(let t=u.length-1;t>=0;t--)if(u[t]>0){u[t]+=i.encodeNormalizedInt(1-e,s);break}for(let t=u.length-1;t>=0;t--)0===u[t]&&(g[t]=0);we(t,n,"JOINTS",g),we(t,n,"WEIGHTS",u,c)}}}(t)}function Me(t,e,n,r,o){let s;const a=[0,0,0,0];for(let c=0;s=t.getAttribute(`${n}_${c}`);c++){s.getElement(e,a);for(let t=0;t<4;t++)r[4*c+t]=o?i.encodeNormalizedInt(a[t],o):a[t]}return r}function we(t,e,n,r,o){let s;const a=[0,0,0,0];for(let c=0;s=t.getAttribute(`${n}_${c}`);c++){for(let t=0;t<4;t++)a[t]=o?i.decodeNormalizedInt(r[4*c+t],o):r[4*c+t];s.setElement(e,a)}}function be(t,e){let n=0;for(let r=0;r<t.length;r++)n+=e?i.decodeNormalizedInt(t[r],e):t[r];return n}const Ne=[Int8Array,Int16Array,Int32Array],{TRANSLATION:Re,ROTATION:Ce,SCALE:Oe,WEIGHTS:ve}=l.TargetPath,Pe=[Re,Ce,Oe],$e={pattern:/.*/,quantizationVolume:"mesh",quantizePosition:14,quantizeNormal:10,quantizeTexcoord:12,quantizeColor:8,quantizeWeight:8,quantizeGeneric:12,normalizeWeights:!0},xe=(t=$e)=>{const n=G({},$e,t);return F("quantize",async t=>{const r=t.getLogger(),o=t.getRoot();let s;t.createExtension(M).setRequired(!0),"scene"===n.quantizationVolume&&(s=Le(function(t){const e=t[0];for(const n of t)lt(e.min,e.min,n.min),gt(e.max,e.max,n.max);return e}(o.listMeshes().map(Be))));for(const e of t.getRoot().listMeshes()){"mesh"===n.quantizationVolume&&(s=Le(Be(e))),s&&n.pattern.test("POSITION")&&(qe(t,e,s),ke(e,1/s.scale));for(const r of e.listPrimitives()){ze(t,r,s,n);for(const e of r.listTargets())ze(t,e,s,n)}}await t.transform(Lt({propertyTypes:[e.ACCESSOR,e.SKIN,e.MATERIAL]}),Nt({propertyTypes:[e.ACCESSOR,e.MATERIAL]})),r.debug("quantize: Complete.")})};function ze(e,n,r,o){const s=e.getLogger();for(const e of n.listSemantics()){if(!o.pattern.test(e))continue;const c=n.getAttribute(e),{bits:l,ctor:g}=Fe(e,c,s,o);if(!g)continue;if(l<8||l>16)throw new Error("quantize: Requires bits = 8–16.");if(c.getComponentSize()<=l/8)continue;const u=c.clone();if("POSITION"===e){const e=r.scale,o=[];n instanceof t?ot(o,We(r)):((i=o)[0]=(a=[1/e,1/e,1/e])[0],i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=a[1],i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=a[2],i[11]=0,i[12]=0,i[13]=0,i[14]=0,i[15]=1);for(let t=0,e=[0,0,0],n=u.getCount();t<n;t++)u.getElement(t,e),u.setElement(t,pt(e,e,o))}Ge(u,g,l),n.swap(c,u)}var i,a;if(o.normalizeWeights&&n.getAttribute("WEIGHTS_0")&&Ie(n,Infinity),n instanceof t&&n.getIndices()&&n.listAttributes().length&&n.listAttributes()[0].getCount()<65535){const t=n.getIndices();t.setArray(new Uint16Array(t.getArray()))}}function Le(t){const{min:e,max:n}=t,r=Math.max((n[0]-e[0])/2,(n[1]-e[1])/2,(n[2]-e[2])/2);return{offset:[e[0]+(n[0]-e[0])/2,e[1]+(n[1]-e[1])/2,e[2]+(n[2]-e[2])/2],scale:r}}function qe(t,e,n){const r=We(n);for(const o of e.listParents()){if(!(o instanceof A))continue;const s=o.listParents().filter(t=>t instanceof l),i=s.some(t=>Pe.includes(t.getTargetPath())),a=o.listChildren().length>0;if(o.getSkin()){o.setSkin(_e(o.getSkin(),n));continue}let c;a||i?(c=t.createNode("").setMesh(e),o.addChild(c).setMesh(null),s.filter(t=>t.getTargetPath()===ve).forEach(t=>t.setTargetNode(c))):c=o;const g=c.getMatrix();st(g,g,r),c.setMatrix(g)}}function _e(t,e){t=t.clone();const n=We(e),r=t.getInverseBindMatrices().clone(),o=[];for(let t=0,e=r.getCount();t<e;t++)r.getElement(t,o),st(o,o,n),r.setElement(t,o);return t.setInverseBindMatrices(r)}function ke(t,e){for(const n of t.listPrimitives()){let t=n.getMaterial();if(!t)continue;let r=t.getExtension("KHR_materials_volume");!r||r.getThicknessFactor()<=0||(r=r.clone().setThicknessFactor(r.getThicknessFactor()*e),t=t.clone().setExtension("KHR_materials_volume",r),n.setMaterial(t))}}function Ge(t,e,n){const r=new e(t.getArray().length),o=Ne.includes(e)?1:0,s=n-o,i=8*e.BYTES_PER_ELEMENT-o,a=Math.pow(2,s)-1,c=i-s,l=2*s-i;for(let e=0,n=0,o=[];e<t.getCount();e++){t.getElement(e,o);for(let t=0;t<o.length;t++){let e=Math.round(Math.abs(o[t])*a);e=e<<c|e>>l,r[n++]=e*Math.sign(o[t])}}t.setArray(r).setNormalized(!0).setSparse(!1)}function Fe(t,e,n,r){const o=e.getMinNormalized([]),s=e.getMaxNormalized([]);let i,a;if("POSITION"===t)i=r.quantizePosition,a=i<=8?Int8Array:Int16Array;else if("NORMAL"===t||"TANGENT"===t)i=r.quantizeNormal,a=i<=8?Int8Array:Int16Array;else if(t.startsWith("COLOR_"))i=r.quantizeColor,a=i<=8?Uint8Array:Uint16Array;else if(t.startsWith("TEXCOORD_")){if(o.some(t=>t<0)||s.some(t=>t>1))return n.warn(`quantize: Skipping ${t}; out of [0,1] range.`),{bits:-1};i=r.quantizeTexcoord,a=i<=8?Uint8Array:Uint16Array}else{if(t.startsWith("JOINTS_"))return i=Math.max(...e.getMax([]))<=255?8:16,a=i<=8?Uint8Array:Uint16Array,e.getComponentSize()>i/8&&e.setArray(new a(e.getArray())),{bits:-1};if(t.startsWith("WEIGHTS_")){if(o.some(t=>t<0)||s.some(t=>t>1))return n.warn(`quantize: Skipping ${t}; out of [0,1] range.`),{bits:-1};i=r.quantizeWeight,a=i<=8?Uint8Array:Uint16Array}else{if(!t.startsWith("_"))throw new Error(`quantize: Unexpected semantic, "${t}".`);if(o.some(t=>t<-1)||s.some(t=>t>1))return n.warn(`quantize: Skipping ${t}; out of [-1,1] range.`),{bits:-1};i=r.quantizeGeneric,a=a=o.some(t=>t<0)?i<=8?Int8Array:Int16Array:i<=8?Uint8Array:Uint16Array}}return{bits:i,ctor:a}}function Be(t){const e=[],n=[];for(const r of t.listPrimitives()){const t=r.getAttribute("POSITION");t&&e.push(t);for(const t of r.listTargets()){const e=t.getAttribute("POSITION");e&&n.push(e)}}if(0===e.length)throw new Error('quantize: Missing "POSITION" attribute.');const r=Ue(e,3);if(n.length>0){const{min:t,max:e}=Ue(n,3);lt(r.min,r.min,lt(t,ut(t,t,2),[0,0,0])),gt(r.max,r.max,gt(e,ut(e,e,2),[0,0,0]))}return r}function Ue(t,e){const n=new Array(e).fill(Infinity),r=new Array(e).fill(-Infinity),o=[],s=[];for(const i of t){i.getMinNormalized(o),i.getMaxNormalized(s);for(let t=0;t<e;t++)n[t]=Math.min(n[t],o[t]),r[t]=Math.max(r[t],s[t])}return{min:n,max:r}}function We(t){return r=t.offset,f=(s=(n=[0,0,0,1])[0])*(l=s+s),p=s*(g=(i=n[1])+i),m=s*(u=(a=n[2])+a),h=i*u,y=(c=n[3])*l,E=c*g,T=c*u,I=(o=[t.scale,t.scale,t.scale])[1],M=o[2],(e=[])[0]=(1-((d=i*g)+(A=a*u)))*(S=o[0]),e[1]=(p+T)*S,e[2]=(m-E)*S,e[3]=0,e[4]=(p-T)*I,e[5]=(1-(f+A))*I,e[6]=(h+y)*I,e[7]=0,e[8]=(m+E)*M,e[9]=(h-y)*M,e[10]=(1-(f+d))*M,e[11]=0,e[12]=r[0],e[13]=r[1],e[14]=r[2],e[15]=1,e;var e,n,r,o,s,i,a,c,l,g,u,f,p,m,d,h,A,y,E,T,S,I,M}const He={level:"high"},je=t=>{const e=G({},He,t),n=e.encoder;if(!n)throw new Error('meshopt: encoder dependency required — install "meshoptimizer".');return F("meshopt",async t=>{await t.transform(Te({encoder:n,target:"size"}),xe({pattern:"medium"===e.level?/.*/:/^(POSITION|TEXCOORD|JOINTS|WEIGHTS)(_\d+)?$/,quantizePosition:14,quantizeTexcoord:12,quantizeColor:8,quantizeNormal:8})),t.createExtension(N).setRequired(!0).setEncoderOptions({method:"medium"===e.level?N.EncoderMethod.QUANTIZE:N.EncoderMethod.FILTER})})},De={};function Ve(t=De){return G({},De,t),F("metalRough",async t=>{const e=t.getLogger();if(!t.getRoot().listExtensionsUsed().map(t=>t.extensionName).includes("KHR_materials_pbrSpecularGlossiness"))return void e.warn("metalRough: KHR_materials_pbrSpecularGlossiness not found on document.");const n=t.createExtension(R),r=t.createExtension(C),o=t.createExtension(O),s=new Set;for(const e of t.getRoot().listMaterials()){const o=e.getExtension("KHR_materials_pbrSpecularGlossiness");if(!o)continue;const i=r.createSpecular().setSpecularFactor(1).setSpecularColorFactor(o.getSpecularFactor());s.add(o.getSpecularGlossinessTexture()),s.add(e.getBaseColorTexture()),s.add(e.getMetallicRoughnessTexture()),e.setBaseColorFactor(o.getDiffuseFactor()).setMetallicFactor(0).setRoughnessFactor(1).setExtension("KHR_materials_ior",n.createIOR().setIOR(1e3)).setExtension("KHR_materials_specular",i);const a=o.getDiffuseTexture();a&&(e.setBaseColorTexture(a),e.getBaseColorTextureInfo().copy(o.getDiffuseTextureInfo()));const c=o.getSpecularGlossinessTexture();if(c){const n=o.getSpecularGlossinessTextureInfo(),r=t.createTexture();await U(c,r,(t,e,n)=>{t.set(e,n,3,255)}),i.setSpecularTexture(r),i.setSpecularColorTexture(r),i.getSpecularTextureInfo().copy(n),i.getSpecularColorTextureInfo().copy(n);const s=o.getGlossinessFactor(),a=t.createTexture();await U(c,a,(t,e,n)=>{const r=255-Math.round(t.get(e,n,3)*s);t.set(e,n,0,0),t.set(e,n,1,r),t.set(e,n,2,0),t.set(e,n,3,255)}),e.setMetallicRoughnessTexture(a),e.getMetallicRoughnessTextureInfo().copy(n)}else i.setSpecularColorFactor(o.getSpecularFactor()),e.setRoughnessFactor(1-o.getGlossinessFactor());e.setExtension("KHR_materials_pbrSpecularGlossiness",null)}o.dispose();for(const t of s)t&&1===t.listParents().length&&t.dispose();e.debug("metalRough: Complete.")})}const Xe={};function Ke(t=Xe){return G({},Xe,t),F("unweld",t=>{const e=t.getLogger(),n=new Map;for(const r of t.getRoot().listMeshes())for(const t of r.listPrimitives()){const r=t.getIndices();if(!r)continue;const o=t.getAttribute("POSITION").getCount();for(const o of t.listAttributes())t.swap(o,Je(o,r,e,n)),1===o.listParents().length&&o.dispose();for(const o of t.listTargets())for(const t of o.listAttributes())o.swap(t,Je(t,r,e,n)),1===t.listParents().length&&t.dispose();const s=t.getAttribute("POSITION").getCount();e.debug(`unweld: ${V(o,s)} vertices.`),t.setIndices(null),1===r.listParents().length&&r.dispose()}e.debug("unweld: Complete.")})}function Je(t,e,n,r){if(r.has(t)&&r.get(t).has(e))return n.debug(`unweld: Cache hit for reused attribute, "${t.getName()}".`),r.get(t).get(e);const o=t.clone(),s=t.getArray().constructor;o.setArray(new s(e.getCount()*t.getElementSize()));const i=[];for(let n=0;n<e.getCount();n++)o.setElement(n,t.getElement(e.getScalar(n),i));return r.has(t)||r.set(t,new Map),r.get(t).set(e,o),o}const Ze={overwrite:!1};function Qe(t=Ze){const e=G({},Ze,t);return F("normals",async t=>{const n=t.getLogger();let r=0;await t.transform(Ke());for(const o of t.getRoot().listMeshes())for(const s of o.listPrimitives()){const o=s.getAttribute("POSITION");let i=s.getAttribute("NORMAL");if(e.overwrite&&i)i.dispose();else if(i){n.debug("normals: Skipping primitive: NORMAL found.");continue}i=t.createAccessor().setArray(new Float32Array(3*o.getCount())).setType("VEC3");const a=[0,0,0],c=[0,0,0],l=[0,0,0];for(let t=0;t<o.getCount();t+=3){o.getElement(t+0,a),o.getElement(t+1,c),o.getElement(t+2,l);const e=Ye(a,c,l);i.setElement(t+0,e),i.setElement(t+1,e),i.setElement(t+2,e)}s.setAttribute("NORMAL",i),r++}r?n.debug("normals: Complete."):n.warn("normals: No qualifying primitives found. See debug output.")})}function Ye(t,e,n){const r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],o=[n[0]-t[0],n[1]-t[1],n[2]-t[2]];return ft([0,0,0],[r[1]*o[2]-r[2]*o[1],r[2]*o[0]-r[0]*o[2],r[0]*o[1]-r[1]*o[0]])}const tn={animations:!0,meshes:!0},en=(t=tn)=>{const n=G({},tn,t);return F("partition",async t=>{const r=t.getLogger();!1!==n.meshes&&function(t,e,n){const r=new Set(t.getRoot().listBuffers().map(t=>t.getURI()));t.getRoot().listMeshes().forEach((o,s)=>{if(Array.isArray(n.meshes)&&!n.meshes.includes(o.getName()))return void e.debug(`partition: Skipping mesh #${s} with name "${o.getName()}".`);e.debug(`partition: Creating buffer for mesh "${o.getName()}".`);const i=t.createBuffer(o.getName()).setURI(nn(o.getName()||"mesh",r));o.listPrimitives().forEach(t=>{const e=t.getIndices();e&&e.setBuffer(i),t.listAttributes().forEach(t=>t.setBuffer(i)),t.listTargets().forEach(t=>{t.listAttributes().forEach(t=>t.setBuffer(i))})})})}(t,r,n),!1!==n.animations&&function(t,e,n){const r=new Set(t.getRoot().listBuffers().map(t=>t.getURI()));t.getRoot().listAnimations().forEach((o,s)=>{if(Array.isArray(n.animations)&&!n.animations.includes(o.getName()))return void e.debug(`partition: Skipping animation #${s} with name "${o.getName()}".`);e.debug(`partition: Creating buffer for animation "${o.getName()}".`);const i=t.createBuffer(o.getName()).setURI(nn(o.getName()||"animation",r));o.listSamplers().forEach(t=>{const e=t.getInput(),n=t.getOutput();e&&e.setBuffer(i),n&&n.setBuffer(i)})})}(t,r,n),n.meshes||n.animations||r.warn("partition: Select animations or meshes to create a partition."),await t.transform(Lt({propertyTypes:[e.BUFFER]})),r.debug("partition: Complete.")})};function nn(t,e){let n=`${t}.bin`,r=1;for(;e.has(n);)n=`${t}_${r++}.bin`;return n}function rn(){var t=new rt(4);return rt!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function on(t,e){var n=an(t,e);return Math.acos(2*n*n-1)}function sn(t,e,n,r){var o,s,i,a,c,l=e[0],g=e[1],u=e[2],f=e[3],p=n[0],m=n[1],d=n[2],h=n[3];return(s=l*p+g*m+u*d+f*h)<0&&(s=-s,p=-p,m=-m,d=-d,h=-h),1-s>1e-6?(o=Math.acos(s),i=Math.sin(o),a=Math.sin((1-r)*o)/i,c=Math.sin(r*o)/i):(a=1-r,c=r),t[0]=a*l+c*p,t[1]=a*g+c*m,t[2]=a*u+c*d,t[3]=a*f+c*h,t}var an=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]};at(),ct(1,0,0),ct(0,1,0),rn(),rn(),it();const cn={tolerance:1e-4},ln=(t=cn)=>{const n=G({},cn,t);return F("resample",async(t,r)=>{const o=new Set,s=t.getRoot().listAccessors().length,i=t.getLogger();let a=!1;for(const e of t.getRoot().listAnimations()){const t=new Map;for(const n of e.listChannels())t.set(n.getSampler(),n.getTargetPath());for(const r of e.listSamplers())"weights"!==t.get(r)?"STEP"!==r.getInterpolation()&&"LINEAR"!==r.getInterpolation()||(o.add(r.getInput()),o.add(r.getOutput()),gn(r,t.get(r),n)):a=!0}for(const t of Array.from(o.values()))t.listParents().some(t=>!(t instanceof c))||t.dispose();t.getRoot().listAccessors().length>s&&!B(r,"resample","dedup")&&await t.transform(Nt({propertyTypes:[e.ACCESSOR]})),a&&i.warn("resample: Skipped optimizing morph target keyframes, not yet supported."),i.debug("resample: Complete.")})};function gn(t,e,n){const r=t.getInput().clone().setSparse(!1),o=t.getOutput().clone().setSparse(!1),s=n.tolerance,a=t.getInterpolation(),c=r.getCount()-1,l=[],g=[],u=[],f=[];let p=1;for(let t=1;t<c;++t){const n=r.getScalar(p-1),c=r.getScalar(t),m=r.getScalar(t+1),d=(c-n)/(m-n);let h=!1;if(c!==m&&(1!==t||c!==r.getScalar(0)))if(o.getElement(p-1,f),o.getElement(t,g),o.getElement(t+1,u),"LINEAR"===a&&"rotation"===e){const t=sn(l,f,u,d),e=on(f,g)+on(g,u);h=!i.eq(g,t,s)||e+Number.EPSILON>=Math.PI}else if("LINEAR"===a){const t=fn(l,f,u,d);h=!i.eq(g,t,s)}else"STEP"===a&&(h=!i.eq(g,f)||!i.eq(g,u));h&&(t!==p&&(r.setScalar(p,r.getScalar(t)),o.setElement(p,o.getElement(t,l))),p++)}c>0&&(r.setScalar(p,r.getScalar(c)),o.setElement(p,o.getElement(c,l)),p++),p!==r.getCount()?(r.setArray(r.getArray().slice(0,p)),o.setArray(o.getArray().slice(0,p*o.getElementSize())),t.setInput(r),t.setOutput(o)):(r.dispose(),o.dispose())}function un(t,e,n){return t*(1-n)+e*n}function fn(t,e,n,r){for(let o=0;o<e.length;o++)t[o]=un(e[o],n[o],r);return t}const pn={name:"",fps:10,pattern:/.*/,sort:!0};function mn(t=pn){const e=G({},pn,t);return F("sequence",t=>{const n=t.getLogger(),r=t.getRoot(),o=e.fps,s=r.listNodes().filter(t=>t.getName().match(e.pattern));e.sort&&s.sort((t,e)=>t.getName()>e.getName()?1:-1);const i=t.createAnimation(e.name),a=r.listBuffers()[0];s.forEach((e,n)=>{let r,c;0===n?(r=[n/o,(n+1)/o],c=[1,1,1,0,0,0]):n===s.length-1?(r=[(n-1)/o,n/o],c=[0,0,0,1,1,1]):(r=[(n-1)/o,n/o,(n+1)/o],c=[0,0,0,1,1,1,0,0,0]);const g=t.createAccessor().setArray(new Float32Array(r)).setBuffer(a),u=t.createAccessor().setArray(new Float32Array(c)).setBuffer(a).setType(y.Type.VEC3),f=t.createAnimationSampler().setInterpolation(E.Interpolation.STEP).setInput(g).setOutput(u),p=t.createAnimationChannel().setTargetNode(e).setTargetPath(l.TargetPath.SCALE).setSampler(f);i.addSampler(f).addChannel(p)}),n.debug("sequence: Complete.")})}const dn={tolerance:1e-4,overwrite:!0,exhaustive:!0};function hn(t=dn){const n=G({},dn,t);if(n.tolerance>.1||n.tolerance<0)throw new Error("weld: Requires 0 ≤ tolerance ≤ 0.1");return F("weld",async t=>{const r=t.getLogger();for(const e of t.getRoot().listMeshes()){for(const r of e.listPrimitives())An(t,r,n),0===r.getIndices().getCount()&&r.dispose();0===e.listPrimitives().length&&e.dispose()}await t.transform(Lt({propertyTypes:[e.ACCESSOR,e.NODE]})),await t.transform(Nt({propertyTypes:[e.ACCESSOR]})),r.debug("weld: Complete.")})}function An(e,n,r){n.getIndices()&&!r.overwrite||n.getMode()!==t.Mode.POINTS&&(0===r.tolerance?function(t,e){if(e.getIndices())return;const n=e.listAttributes()[0],r=n.getCount(),o=n.getBuffer(),s=t.createAccessor().setBuffer(o).setType(y.Type.SCALAR).setArray(Z(r));e.setIndices(s)}(e,n):function(t,e,n){const r=t.getLogger(),o=e.getAttribute("POSITION"),s=e.getIndices()||t.createAccessor().setArray(Z(o.getCount())),i=new Uint32Array(new Set(s.getArray())).sort(),a=Math.max(n.tolerance,Number.EPSILON),c={};for(const t of e.listSemantics()){const n=e.getAttribute(t);c[t]=Sn(t,n,a)}var l;r.debug(`weld: Tolerance thresholds: ${l=c,Object.entries(l).map(([t,e])=>`${t}=${e}`).join(", ")}`);const g=[0,0,0],u=[0,0,0],f={},p=c.POSITION;for(let t=0;t<i.length;t++){o.getElement(i[t],g);const e=bn(g,p);f[e]=f[e]||[],f[e].push(i[t])}const m=Z(i.length),d=new Array(i.length).fill(-1),h=o.getCount();let A=0;for(let t=0;t<i.length;t++){const r=i[t];o.getElement(r,g);const s=n.exhaustive?wn(g,p):[bn(g,p)];t:for(const t of s)if(f[t])e:for(const n of f[t]){const t=m[n];if(r<=t)continue e;o.getElement(t,u);const s=e.listSemantics().every(n=>In(e.getAttribute(n),r,t,c[n])),i=e.listTargets().every(e=>e.listSemantics().every(n=>In(e.getAttribute(n),r,t,c[n])));if(s&&i){m[r]=t;break t}}d[r]=m[r]===r?A++:d[m[r]]}r.debug(`weld: ${V(h,A)} vertices.`);const y=s.getCount(),E=Z(y,i.length);for(let t=0;t<y;t++)E[t]=d[s.getScalar(t)];e.setIndices(s.clone().setArray(E)),1===s.listParents().length&&s.dispose();for(const t of e.listAttributes())yn(e,t,d,A);for(const t of e.listTargets())for(const e of t.listAttributes())yn(t,e,d,A);!function(t){const e=t.getIndices();if(!e)return;const n=[];let r=-Infinity;for(let t=0,o=e.getCount();t<o;t+=3){const o=e.getScalar(t),s=e.getScalar(t+1),i=e.getScalar(t+2);o!==s&&o!==i&&s!==i&&(n.push(o,s,i),r=Math.max(r,o,s,i))}const o=Z(n.length,r);o.set(n),e.setArray(o)}(e)}(e,n,r))}function yn(t,e,n,r){const o=(a=e.getArray(),c=r*e.getElementSize(),new(0,a.constructor)(c)),s=e.clone().setArray(o),i=new Uint8Array(r);var a,c;for(let t=0,r=[];t<n.length;t++)i[n[t]]||(s.setElement(n[t],e.getElement(t,r)),i[n[t]]=1);t.swap(e,s),1===e.listParents().length&&e.dispose()}const En=[],Tn=[];function Sn(t,e,n){return"NORMAL"===t||"TANGENT"===t?.5:t.startsWith("COLOR_")?.01:t.startsWith("TEXCOORD_")?1e-4:t.startsWith("JOINTS_")?0:t.startsWith("WEIGHTS_")?.01:(En.length=Tn.length=0,e.getMinNormalized(En),e.getMaxNormalized(Tn),n*(Math.max(...Tn)-Math.min(...En)||1))}function In(t,e,n,r,o){t.getElement(e,En),t.getElement(n,Tn);for(let e=0,n=t.getElementSize();e<n;e++)if(Math.abs(En[e]-Tn[e])>r)return!1;return!0}const Mn=[0,-1,1];function wn(t,e){const n=[],r=[0,0,0];for(const o of Mn)for(const s of Mn)for(const i of Mn)r[0]=t[0]+o*e,r[1]=t[1]+s*e,r[2]=t[2]+i*e,n.push(bn(r,e));return n}function bn(t,e){return Math.round(t[0]/e)+":"+Math.round(t[1]/e)+":"+Math.round(t[2]/e)}const Nn={ratio:.5,error:.001,lockBorder:!1},Rn=n=>{const r=G({},Nn,n),o=r.simplifier;if(!o)throw new Error('simplify: simplifier dependency required — install "meshoptimizer".');return F("simplify",async(n,s)=>{const i=n.getLogger();await o.ready,await n.transform(hn({overwrite:!1}));for(const e of n.getRoot().listMeshes())for(const o of e.listPrimitives())o.getMode()===t.Mode.TRIANGLES?Cn(n,o,r):i.warn(`simplify: Skipping primitive of mesh "${e.getName()}": Requires TRIANGLES draw mode.`);B(s,"simplify","dedup")||await n.transform(Nt({propertyTypes:[e.ACCESSOR]})),i.debug("simplify: Complete.")})};function Cn(t,e,n){const r=G({},Nn,n),o=r.simplifier,s=t.getLogger(),i=e.getAttribute("POSITION"),a=e.getIndices(),c=i.getCount();let l=i.getArray(),g=a.getArray();if(i.getComponentType()!==y.ComponentType.FLOAT)if(i.getNormalized()){const t=l,e=new Float32Array(t.length);for(let n=0,r=i.getCount(),o=[];n<r;n++)o=i.getElement(n,o),i.setArray(e).setElement(n,o).setArray(t);l=e}else l=new Float32Array(l);a.getComponentType()!==y.ComponentType.UNSIGNED_INT&&(g=new Uint32Array(g));const u=3*Math.floor(r.ratio*c/3),[f,p]=o.simplify(g,l,3,u,r.error,r.lockBorder?["LockBorder"]:[]),[m,d]=o.compactMesh(f);s.debug(`simplify: ${V(i.getCount(),d)} vertices, error: ${p.toFixed(4)}.`);for(const t of X(e)){const n=t.clone();J(n,m,d),K(e,t,n),1===t.listParents().length&&t.dispose()}const h=a.clone();return h.setArray(c<=65534?new Uint16Array(f):f),e.setIndices(h),1===a.listParents().length&&a.dispose(),e}const On={ratio:1/3};function vn(t=On){const e=G({},On,t).ratio;if(e<0||e>1)throw new Error("sparse: Ratio must be between 0 and 1.");return F("sparse",t=>{const n=t.getRoot(),r=t.getLogger();let o=0;for(const t of n.listAccessors()){const n=t.getCount(),r=Array(t.getElementSize()).fill(0),s=Array(t.getElementSize()).fill(0);let a=0;for(let o=0;o<n&&(t.getElement(o,s),i.eq(s,r,0)||a++,!(a/n>=e));o++);const c=a/n<e;c!==t.getSparse()&&(t.setSparse(c),o++)}r.debug(`sparse: Updated ${o} accessors.`),r.debug("sparse: Complete.")})}const Pn="textureResize";var $n;!function(t){t.LANCZOS3="lanczos3",t.LANCZOS2="lanczos2"}($n||($n={}));const xn={size:[2048,2048],filter:$n.LANCZOS3,pattern:null,slots:null};function zn(t=xn){const e=G({},xn,t);return F(Pn,async t=>{const n=t.getLogger();for(const r of t.getRoot().listTextures()){const t=r.getName(),o=r.getURI();if(e.pattern&&!e.pattern.test(t)&&!e.pattern.test(o)){n.debug(`${Pn}: Skipping, excluded by "pattern" parameter.`);continue}if("image/png"!==r.getMimeType()&&"image/jpeg"!==r.getMimeType()){n.warn(`${Pn}: Skipping, unsupported texture type "${r.getMimeType()}".`);continue}const s=ye(r);if(e.slots&&!s.some(t=>{var n;return null==(n=e.slots)?void 0:n.test(t)})){n.debug(`${Pn}: Skipping, [${s.join(", ")}] excluded by "slots" parameter.`);continue}const[i,a]=e.size,[c,l]=r.getSize();if(c<=i&&l<=a){n.debug(`${Pn}: Skipping, not within size range.`);continue}let g=c,u=l;g>i&&(u=Math.floor(u*(i/g)),g=i),u>a&&(g=Math.floor(g*(a/u)),u=a);const f=r.getImage(),p=await S(f,r.getMimeType()),m=q(new Uint8Array(g*u*4),[g,u,4]);n.debug(`${Pn}: Resizing "${o||t}", ${p.shape} → ${m.shape}...`),n.debug(`${Pn}: Slots → [${s.join(", ")}]`);try{e.filter===$n.LANCZOS3?_(p,m):k(p,m)}catch(e){if(e instanceof Error){n.warn(`${Pn}: Failed to resize "${o||t}": "${e.message}".`);continue}throw e}r.setImage(await I(m,r.getMimeType()))}n.debug(`${Pn}: Complete.`)})}const Ln="textureCompress",qn=["jpeg","png","webp","avif"],_n=["image/jpeg","image/png","image/webp","image/avif"],kn={resizeFilter:$n.LANCZOS3,pattern:null,formats:null,slots:null,quality:null,effort:null,lossless:!1,nearLossless:!1},Gn=function(t){const e=G({},kn,t),n=e.targetFormat,r=e.pattern,o=e.formats,s=e.slots;if(!e.encoder)throw new Error(`${n}: encoder dependency required — install "sharp".`);return F(Ln,async t=>{const i=t.getLogger(),a=t.getRoot().listTextures();await Promise.all(a.map(async(a,c)=>{const l=ye(a),g=he(a),u=a.getURI()||a.getName()||`${c+1}/${t.getRoot().listTextures().length}`,f=`${Ln}(${u})`;if(!_n.includes(a.getMimeType()))return void i.debug(`${f}: Skipping, unsupported texture type "${a.getMimeType()}".`);if(r&&!r.test(a.getName())&&!r.test(a.getURI()))return void i.debug(`${f}: Skipping, excluded by "pattern" parameter.`);if(o&&!o.test(a.getMimeType()))return void i.debug(`${f}: Skipping, "${a.getMimeType()}" excluded by "formats" parameter.`);if(s&&l.length&&!l.some(t=>s.test(t)))return void i.debug(`${f}: Skipping, [${l.join(", ")}] excluded by "slots" parameter.`);if("jpeg"===e.targetFormat&&g&h.A)return void i.warn(`${f}: Skipping, [${l.join(", ")}] requires alpha channel.`);const p=Bn(a);i.debug(`${f}: Format = ${p} → ${n||p}`),i.debug(`${f}: Slots = [${l.join(", ")}]`);const m=a.getImage(),d=m.byteLength;await Fn(a,e);const A=a.getImage(),y=A.byteLength,E=m===A?" (SKIPPED":"";i.debug(`${f}: Size = ${j(d)} → ${j(y)}${E}`)}));const c=t.createExtension(v);a.some(t=>"image/webp"===t.getMimeType())?c.setRequired(!0):c.dispose();const l=t.createExtension(P);a.some(t=>"image/avif"===t.getMimeType())?l.setRequired(!0):l.dispose(),i.debug(`${Ln}: Complete.`)})};async function Fn(t,e){const n=G({},kn,e),r=n.encoder;if(!r)throw new Error(`${n.targetFormat}: encoder dependency required — install "sharp".`);const o=Bn(t),s=n.targetFormat||o,i=t.getMimeType(),c=`image/${s}`;let l={};switch(s){case"jpeg":l={quality:n.quality};break;case"png":l={quality:n.quality,effort:Un(n.effort,100,10)};break;case"webp":l={quality:n.quality,effort:Un(n.effort,100,6),lossless:n.lossless,nearLossless:n.nearLossless};break;case"avif":l={quality:n.quality,effort:Un(n.effort,100,9),lossless:n.lossless}}const g=t.getImage(),u=r(g).toFormat(s,l);n.resize&&u.resize(n.resize[0],n.resize[1],{fit:"inside",kernel:n.resizeFilter,withoutEnlargement:!0});const f=a.toView(await u.toBuffer());if(!(i===c&&f.byteLength>=g.byteLength))if(i===c)t.setImage(f);else{const e=p.mimeTypeToExtension(i),n=p.mimeTypeToExtension(c),r=t.getURI().replace(new RegExp(`\\.${e}$`),`.${n}`);t.setImage(f).setMimeType(c).setURI(r)}}function Bn(t){const e=t.getMimeType(),n=e.split("/").pop();if(!n||!qn.includes(n))throw new Error(`Unknown MIME type "${e}".`);return n}function Un(t,e,n){return null==t?null:Math.round(t/e*n)}const Wn={overwrite:!1};function Hn(t=Wn){if(!t.generateTangents)throw new Error('tangents: generateTangents callback required — install "mikktspace".');const e=G({},Wn,t);return F("tangents",t=>{const n=t.getLogger(),r=new Map,o=new Map;let s=0;for(const i of t.getRoot().listMeshes()){const a=i.getName(),c=i.listPrimitives();for(let i=0;i<c.length;i++){const l=c[i];if(!Dn(l,n,a,i,e.overwrite))continue;const g=jn(l),u=l.getAttribute("POSITION").getArray(),f=l.getAttribute("NORMAL").getArray(),p=l.getAttribute(g).getArray(),m=r.get(u)||T();r.set(u,m);const d=r.get(f)||T();r.set(f,d);const h=r.get(p)||T();r.set(p,h);const A=l.getAttribute("TANGENT");A&&2===A.listParents().length&&A.dispose();const y=`${m}|${d}|${h}`;let E=o.get(y);if(E){n.debug(`tangents: Found cache for primitive ${i} of mesh "${a}".`),l.setAttribute("TANGENT",E),s++;continue}n.debug(`tangents: Generating for primitive ${i} of mesh "${a}".`);const S=l.getAttribute("POSITION").getBuffer(),I=e.generateTangents(u instanceof Float32Array?u:new Float32Array(u),f instanceof Float32Array?f:new Float32Array(f),p instanceof Float32Array?p:new Float32Array(p));for(let t=3;t<I.length;t+=4)I[t]*=-1;E=t.createAccessor().setBuffer(S).setArray(I).setType("VEC4"),l.setAttribute("TANGENT",E),o.set(y,E),s++}}s?n.debug("tangents: Complete."):n.warn("tangents: No qualifying primitives found. See debug output.")})}function jn(t){const e=t.getMaterial();if(!e)return"TEXCOORD_0";const n=e.getNormalTextureInfo();if(!n)return"TEXCOORD_0";const r=`TEXCOORD_${n.getTexCoord()}`;return t.getAttribute(r)?r:"TEXCOORD_0"}function Dn(e,n,r,o,s){return e.getMode()===t.Mode.TRIANGLES&&e.getAttribute("POSITION")&&e.getAttribute("NORMAL")&&e.getAttribute("TEXCOORD_0")?e.getAttribute("TANGENT")&&!s?(n.debug(`tangents: Skipping primitive ${o} of mesh "${r}": TANGENT found.`),!1):!e.getIndices()||(n.warn(`tangents: Skipping primitive ${o} of mesh "${r}": primitives must be unwelded.`),!1):(n.debug(`tangents: Skipping primitive ${o} of mesh "${r}": primitives must have attributes=[POSITION, NORMAL, TEXCOORD_0] and mode=TRIANGLES.`),!1)}const Vn=()=>t=>{const e=t.createExtension($).createUnlit();t.getRoot().listMaterials().forEach(t=>{t.setExtension("KHR_materials_unlit",e)})},Xn={},Kn=(t=Xn)=>(G({},Xn,t),F("unpartition",async t=>{const e=t.getLogger(),n=t.getRoot().listBuffers()[0];t.getRoot().listAccessors().forEach(t=>t.setBuffer(n)),t.getRoot().listBuffers().forEach((t,e)=>e>0?t.dispose():null),e.debug("unpartition: Complete.")}));export{$t as DRACO_DEFAULTS,kt as FLATTEN_DEFAULTS,ge as JOIN_DEFAULTS,He as MESHOPT_DEFAULTS,$e as QUANTIZE_DEFAULTS,Nn as SIMPLIFY_DEFAULTS,kn as TEXTURE_COMPRESS_DEFAULTS,xn as TEXTURE_RESIZE_DEFAULTS,$n as TextureResizeFilter,dn as WELD_DEFAULTS,tt as center,nt as clearNodeParent,It as clearNodeTransform,wt as colorspace,Fn as compressTexture,Se as createLayoutPlan,F as createTransform,Nt as dedup,Ot as dequantize,xt as draco,Gt as flatten,W as getGLPrimitiveCount,Ft as getNodeScene,he as getTextureChannelMask,Bt as inspect,Qt as instance,B as isTransformPending,ue as join,ne as joinPrimitives,et as listNodeScenes,de as listTextureChannels,Ae as listTextureInfo,ye as listTextureSlots,je as meshopt,Ve as metalRough,Qe as normals,en as partition,Lt as prune,xe as quantize,Te as reorder,ln as resample,mn as sequence,Rn as simplify,Cn as simplifyPrimitive,Ie as sortPrimitiveWeights,vn as sparse,Hn as tangents,Gn as textureCompress,zn as textureResize,Tt as transformMesh,ht as transformPrimitive,Vn as unlit,Kn as unpartition,Ke as unweld,hn as weld,An as weldPrimitive}; | ||
//# sourceMappingURL=functions.modern.js.map |
@@ -8,2 +8,3 @@ import { Document, Primitive, Transform } from '@gltf-transform/core'; | ||
overwrite?: boolean; | ||
exhaustive?: boolean; | ||
} | ||
@@ -10,0 +11,0 @@ export declare const WELD_DEFAULTS: Required<WeldOptions>; |
{ | ||
"name": "@gltf-transform/functions", | ||
"version": "3.1.2", | ||
"version": "3.1.3", | ||
"repository": "github:donmccurdy/glTF-Transform", | ||
@@ -38,4 +38,4 @@ "homepage": "https://gltf-transform.donmccurdy.com/functions.html", | ||
"dependencies": { | ||
"@gltf-transform/core": "^3.1.2", | ||
"@gltf-transform/extensions": "^3.1.2", | ||
"@gltf-transform/core": "^3.1.3", | ||
"@gltf-transform/extensions": "^3.1.3", | ||
"ktx-parse": "^0.5.0", | ||
@@ -56,3 +56,3 @@ "ndarray": "^1.0.19", | ||
}, | ||
"gitHead": "7a7621cad44f8890233f7867841f8e039b49cd28" | ||
"gitHead": "50786ecf3fd234f48cb61802343fd8c373d854c7" | ||
} |
163
src/weld.ts
@@ -8,9 +8,39 @@ import { | ||
Transform, | ||
TransformContext, | ||
TypedArray, | ||
vec3, | ||
} from '@gltf-transform/core'; | ||
import { cleanPrimitive } from './clean-primitive.js'; | ||
import { dedup } from './dedup.js'; | ||
import { createIndices, createTransform, formatDeltaOp, isTransformPending } from './utils.js'; | ||
import { prune } from './prune.js'; | ||
import { createIndices, createTransform, formatDeltaOp } from './utils.js'; | ||
// DEVELOPER NOTES: Ideally a weld() implementation should be fast, robust, | ||
// and tunable. The writeup below tracks my attempts to solve for these | ||
// constraints. | ||
// | ||
// (Approach #1) Follow the mergeVertices() implementation of three.js, | ||
// hashing vertices with a string concatenation of all vertex attributes. | ||
// The approach does not allow per-attribute tolerance in local units. | ||
// | ||
// (Approach #2) Sort points along the X axis, then make cheaper | ||
// searches up/down the sorted list for merge candidates. While this allows | ||
// simpler comparison based on specified tolerance, it's much slower, even | ||
// for cases where choice of the X vs. Y or Z axes is reasonable. | ||
// | ||
// (Approach #3) Attempted a Delaunay triangulation in three dimensions, | ||
// expecting it would be an n * log(n) algorithm, but the only implementation | ||
// I found (with delaunay-triangulate) appeared to be much slower than that, | ||
// and was notably slower than the sort-based approach, just building the | ||
// Delaunay triangulation alone. | ||
// | ||
// (Approach #4) Hybrid of (1) and (2), assigning vertices to a spatial | ||
// grid, then searching the local neighborhood (27 cells) for weld candidates. | ||
// | ||
// RESULTS: For the "Lovecraftian" sample model, after joining, a primitive | ||
// with 873,000 vertices can be welded down to 230,000 vertices. Results: | ||
// - (1) Not tested, but prior results suggest not robust enough. | ||
// - (2) 30 seconds | ||
// - (3) 660 seconds | ||
// - (4) 5 seconds exhaustive, 1.5s non-exhaustive | ||
const NAME = 'weld'; | ||
@@ -33,2 +63,3 @@ | ||
overwrite?: boolean; | ||
exhaustive?: boolean; | ||
} | ||
@@ -39,2 +70,3 @@ | ||
overwrite: true, | ||
exhaustive: true, | ||
}; | ||
@@ -71,3 +103,3 @@ | ||
return createTransform(NAME, async (doc: Document, context?: TransformContext): Promise<void> => { | ||
return createTransform(NAME, async (doc: Document): Promise<void> => { | ||
const logger = doc.getLogger(); | ||
@@ -78,11 +110,12 @@ | ||
weldPrimitive(doc, prim, options); | ||
if (prim.getIndices()!.getCount() === 0) prim.dispose(); | ||
} | ||
} | ||
// TODO(perf): Suppose we just invoked simplify(), and dedup is not explicitly | ||
// in the transform stack .... now we are going to run it twice! | ||
if (!isTransformPending(context, NAME, 'dedup')) { | ||
await doc.transform(dedup({ propertyTypes: [PropertyType.ACCESSOR] })); | ||
if (mesh.listPrimitives().length === 0) mesh.dispose(); | ||
} | ||
await doc.transform(prune({ propertyTypes: [PropertyType.ACCESSOR, PropertyType.NODE] })); | ||
await doc.transform(dedup({ propertyTypes: [PropertyType.ACCESSOR] })); | ||
logger.debug(`${NAME}: Complete.`); | ||
@@ -149,11 +182,11 @@ }); | ||
const srcIndices = prim.getIndices() || doc.createAccessor().setArray(createIndices(srcPosition.getCount())); | ||
const uniqueIndices = new Uint32Array(new Set(srcIndices.getArray()!)); | ||
const uniqueIndices = new Uint32Array(new Set(srcIndices.getArray()!)).sort(); | ||
// (1) Compute per-attribute tolerances, pre-sort vertices. | ||
// (1) Compute per-attribute tolerance and spatial grid for vertices. | ||
const tolerance = Math.max(options.tolerance, Number.EPSILON); | ||
const baseTolerance = Math.max(options.tolerance, Number.EPSILON); | ||
const attributeTolerance: Record<string, number> = {}; | ||
for (const semantic of prim.listSemantics()) { | ||
const attribute = prim.getAttribute(semantic)!; | ||
attributeTolerance[semantic] = getAttributeTolerance(semantic, attribute, tolerance); | ||
attributeTolerance[semantic] = getAttributeTolerance(semantic, attribute, baseTolerance); | ||
} | ||
@@ -163,59 +196,68 @@ | ||
// (2) Compare and identify vertices to weld. | ||
const posA: vec3 = [0, 0, 0]; | ||
const posB: vec3 = [0, 0, 0]; | ||
uniqueIndices.sort((a, b) => { | ||
srcPosition.getElement(a, posA); | ||
srcPosition.getElement(b, posB); | ||
return posA[0] > posB[0] ? 1 : -1; | ||
}); | ||
const grid = {} as Record<string, number[]>; | ||
const cellSize = attributeTolerance.POSITION; | ||
// (2) Compare and identify vertices to weld. Use sort to keep iterations below O(n²), | ||
for (let i = 0; i < uniqueIndices.length; i++) { | ||
srcPosition.getElement(uniqueIndices[i], posA); | ||
const key = getGridKey(posA, cellSize); | ||
grid[key] = grid[key] || []; | ||
grid[key].push(uniqueIndices[i]); | ||
} | ||
// (2) Compare and identify vertices to weld. | ||
const weldMap = createIndices(uniqueIndices.length); // oldIndex → oldCommonIndex | ||
const writeMap = createIndices(uniqueIndices.length); // oldIndex → newIndex | ||
const writeMap = new Array(uniqueIndices.length).fill(-1); // oldIndex → newIndex | ||
const srcVertexCount = srcPosition.getCount(); | ||
let dstVertexCount = 0; | ||
let backIters = 0; | ||
for (let i = 0; i < uniqueIndices.length; i++) { | ||
const a = uniqueIndices[i]; | ||
srcPosition.getElement(a, posA); | ||
for (let j = i - 1; j >= 0; j--) { | ||
const b = weldMap[uniqueIndices[j]]; | ||
const cellKeys = options.exhaustive ? getGridNeighborhoodKeys(posA, cellSize) : [getGridKey(posA, cellSize)]; | ||
srcPosition.getElement(a, posA); | ||
srcPosition.getElement(b, posB); | ||
cells: for (const cellKey of cellKeys) { | ||
if (!grid[cellKey]) continue cells; // May occur in exhaustive search. | ||
// Sort order allows early exit on X-axis distance. | ||
if (Math.abs(posA[0] - posB[0]) > attributeTolerance['POSITION']) { | ||
break; | ||
} | ||
neighbors: for (const j of grid[cellKey]) { | ||
const b = weldMap[j]; | ||
backIters++; | ||
// Only weld to lower indices, preventing two-way match. | ||
if (a <= b) continue neighbors; | ||
// Weld if base attributes and morph target attributes match. | ||
const isBaseMatch = prim.listSemantics().every((semantic) => { | ||
const attribute = prim.getAttribute(semantic)!; | ||
const tolerance = attributeTolerance[semantic]; | ||
return compareAttributes(attribute, a, b, tolerance, semantic); | ||
}); | ||
const isTargetMatch = prim.listTargets().every((target) => { | ||
return target.listSemantics().every((semantic) => { | ||
const attribute = target.getAttribute(semantic)!; | ||
srcPosition.getElement(b, posB); | ||
// Weld if base attributes and morph target attributes match. | ||
const isBaseMatch = prim.listSemantics().every((semantic) => { | ||
const attribute = prim.getAttribute(semantic)!; | ||
const tolerance = attributeTolerance[semantic]; | ||
return compareAttributes(attribute, a, b, tolerance, semantic); | ||
}); | ||
}); | ||
const isTargetMatch = prim.listTargets().every((target) => { | ||
return target.listSemantics().every((semantic) => { | ||
const attribute = target.getAttribute(semantic)!; | ||
const tolerance = attributeTolerance[semantic]; | ||
return compareAttributes(attribute, a, b, tolerance, semantic); | ||
}); | ||
}); | ||
if (isBaseMatch && isTargetMatch) { | ||
weldMap[a] = b; | ||
break; | ||
if (isBaseMatch && isTargetMatch) { | ||
weldMap[a] = b; | ||
break cells; | ||
} | ||
} | ||
} | ||
// Output the vertex if we didn't find a match, else record the index of the match. | ||
// Output the vertex if we didn't find a match, else record the index of the match. Because | ||
// we iterate vertices in ascending order, and only match to lower indices, we're | ||
// guaranteed the source vertex for a weld has already been marked for output. | ||
if (weldMap[a] === a) { | ||
writeMap[a] = dstVertexCount++; // note: reorders the primitive on x-axis sort. | ||
writeMap[a] = dstVertexCount++; | ||
} else { | ||
@@ -226,3 +268,2 @@ writeMap[a] = writeMap[weldMap[a]]; | ||
logger.debug(`${NAME}: Iterations per vertex: ${Math.round(backIters / uniqueIndices.length)} (avg)`); | ||
logger.debug(`${NAME}: ${formatDeltaOp(srcVertexCount, dstVertexCount)} vertices.`); | ||
@@ -250,2 +291,6 @@ | ||
} | ||
// (5) Clean up degenerate triangles. | ||
cleanPrimitive(prim); | ||
} | ||
@@ -263,3 +308,3 @@ | ||
srcAttr: Accessor, | ||
reorder: Uint32Array | Uint16Array, | ||
reorder: number[], | ||
dstCount: number | ||
@@ -321,1 +366,27 @@ ): void { | ||
} | ||
// Order to search nearer cells first. | ||
const CELL_OFFSETS = [0, -1, 1]; | ||
function getGridNeighborhoodKeys(p: vec3, cellSize: number): string[] { | ||
const keys = [] as string[]; | ||
const _p = [0, 0, 0] as vec3; | ||
for (const i of CELL_OFFSETS) { | ||
for (const j of CELL_OFFSETS) { | ||
for (const k of CELL_OFFSETS) { | ||
_p[0] = p[0] + i * cellSize; | ||
_p[1] = p[1] + j * cellSize; | ||
_p[2] = p[2] + k * cellSize; | ||
keys.push(getGridKey(_p, cellSize)); | ||
} | ||
} | ||
} | ||
return keys; | ||
} | ||
function getGridKey(p: vec3, cellSize: number): string { | ||
const cellX = Math.round(p[0] / cellSize); | ||
const cellY = Math.round(p[1] / cellSize); | ||
const cellZ = Math.round(p[2] / cellSize); | ||
return cellX + ':' + cellY + ':' + cellZ; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1167117
90
6324