@polarfront-lab/ionian 1.7.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ionian.iife.js +1 -1
- package/dist/ionian.iife.js.map +1 -1
- package/dist/ionian.js +70 -9
- package/dist/ionian.js.map +1 -1
- package/package.json +2 -2
package/dist/ionian.iife.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var ionian=function(e,t,i){"use strict";var s=Object.defineProperty,n=(e,t,i)=>((e,t,i)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i)(e,"symbol"!=typeof t?t+"":t,i);function r(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const s=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,s.get?s:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const a=r(t),o=e=>e;class l{constructor(){var e;n(this,"emitter",{all:e=e||new Map,on:function(t,i){var s=e.get(t);s?s.push(i):e.set(t,[i])},off:function(t,i){var s=e.get(t);s&&(i?s.splice(s.indexOf(i)>>>0,1):e.set(t,[]))},emit:function(t,i){var s=e.get(t);s&&s.slice().map((function(e){e(i)})),(s=e.get("*"))&&s.slice().map((function(e){e(t,i)}))}})}emit(e,t){this.emitter.emit(e,t)}off(e,t){this.emitter.off(e,t)}on(e,t){this.emitter.on(e,t)}once(e,t){this.emitter.on(e,(i=>{this.emitter.off(e,t),t(i)}))}dispose(){this.emitter.all.clear()}}function u(e,t){const i=new a.DataTexture(e,t,t,a.RGBAFormat,a.FloatType);return i.needsUpdate=!0,i}function c(e){e.geometry.dispose(),e.material instanceof a.Material?e.material.dispose():e.material.forEach((e=>e.dispose()))}function h(e,t,i){return e=Math.min(e,i),e=Math.max(e,t)}class d{constructor(e){n(this,"serviceState","created"),n(this,"eventEmitter"),n(this,"meshes",new Map),n(this,"textures",new Map),n(this,"gltfLoader",new i.GLTFLoader),n(this,"textureLoader",new a.TextureLoader),n(this,"dracoLoader",new i.DRACOLoader),n(this,"solidColorTexture",new a.DataTexture(new Uint8Array([127,127,127,255]),1,1,a.RGBAFormat)),this.eventEmitter=e,this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/"),this.gltfLoader.setDRACOLoader(this.dracoLoader),this.updateServiceState("ready")}register(e,t){if(t.name=e,t instanceof a.Mesh){const i=this.meshes.get(e);i&&c(i),this.meshes.set(e,t)}else{const i=this.textures.get(e);i&&i.dispose(),this.textures.set(e,t)}this.eventEmitter.emit("assetRegistered",{id:e})}setSolidColor(e){this.changeColor(e)}getSolidColorTexture(){return this.solidColorTexture}getMesh(e){return this.meshes.get(e)??null}getMatcap(e){const t=this.textures.get(e);return t||this.eventEmitter.emit("invalidRequest",{message:`texture with id "${e}" not found. using solid color texture instead...`}),t??this.solidColorTexture}getMeshIDs(){return Array.from(this.meshes.keys())}getTextureIDs(){return Array.from(this.textures.keys())}getMeshes(){return Array.from(this.meshes.values())}getTextures(){return Array.from(this.textures.values())}hasMatcap(e){return this.textures.has(e)}async loadMeshAsync(e,t,i={}){const s=await this.gltfLoader.loadAsync(t);try{if(i.meshName){const t=s.scene.getObjectByName(i.meshName);return this.register(e,t),t}{const t=s.scene.children[0];return this.register(e,t),t}}catch(n){return this.eventEmitter.emit("invalidRequest",{message:`failed to load mesh: ${e}. ${n}`}),null}}async loadTextureAsync(e,t){try{const i=await this.textureLoader.loadAsync(t);return this.register(e,i),i}catch(i){return this.eventEmitter.emit("invalidRequest",{message:`failed to load texture: ${e}. ${i}`}),null}}dispose(){this.updateServiceState("disposed"),this.meshes.forEach((e=>c(e))),this.meshes.clear(),this.textures.forEach((e=>e.dispose())),this.textures.clear()}changeColor(e){const t=new a.Color(e);this.solidColorTexture=new a.DataTexture(new Uint8Array([t.r,t.g,t.b,255]),1,1,a.RGBAFormat),this.solidColorTexture.needsUpdate=!0}updateServiceState(e){this.serviceState=e,this.eventEmitter.emit("serviceStateUpdated",{type:"asset",state:e})}}const m=new t.Triangle,g=new t.Vector3,p=new t.Vector2,v=new t.Vector2,f=new t.Vector2;class x{constructor(e){this.geometry=e.geometry,this.randomFunction=Math.random,this.indexAttribute=this.geometry.index,this.positionAttribute=this.geometry.getAttribute("position"),this.normalAttribute=this.geometry.getAttribute("normal"),this.colorAttribute=this.geometry.getAttribute("color"),this.uvAttribute=this.geometry.getAttribute("uv"),this.weightAttribute=null,this.distribution=null}setWeightAttribute(e){return this.weightAttribute=e?this.geometry.getAttribute(e):null,this}build(){const e=this.indexAttribute,t=this.positionAttribute,i=this.weightAttribute,s=e?e.count/3:t.count/3,n=new Float32Array(s);for(let o=0;o<s;o++){let s=1,r=3*o,a=3*o+1,l=3*o+2;e&&(r=e.getX(r),a=e.getX(a),l=e.getX(l)),i&&(s=i.getX(r)+i.getX(a)+i.getX(l)),m.a.fromBufferAttribute(t,r),m.b.fromBufferAttribute(t,a),m.c.fromBufferAttribute(t,l),s*=m.getArea(),n[o]=s}const r=new Float32Array(s);let a=0;for(let o=0;o<s;o++)a+=n[o],r[o]=a;return this.distribution=r,this}setRandomGenerator(e){return this.randomFunction=e,this}sample(e,t,i,s){const n=this.sampleFaceIndex();return this.sampleFace(n,e,t,i,s)}sampleFaceIndex(){const e=this.distribution[this.distribution.length-1];return this.binarySearch(this.randomFunction()*e)}binarySearch(e){const t=this.distribution;let i=0,s=t.length-1,n=-1;for(;i<=s;){const r=Math.ceil((i+s)/2);if(0===r||t[r-1]<=e&&t[r]>e){n=r;break}e<t[r]?s=r-1:i=r+1}return n}sampleFace(e,t,i,s,n){let r=this.randomFunction(),a=this.randomFunction();r+a>1&&(r=1-r,a=1-a);const o=this.indexAttribute;let l=3*e,u=3*e+1,c=3*e+2;return o&&(l=o.getX(l),u=o.getX(u),c=o.getX(c)),m.a.fromBufferAttribute(this.positionAttribute,l),m.b.fromBufferAttribute(this.positionAttribute,u),m.c.fromBufferAttribute(this.positionAttribute,c),t.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),void 0!==i&&(void 0!==this.normalAttribute?(m.a.fromBufferAttribute(this.normalAttribute,l),m.b.fromBufferAttribute(this.normalAttribute,u),m.c.fromBufferAttribute(this.normalAttribute,c),i.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)).normalize()):m.getNormal(i)),void 0!==s&&void 0!==this.colorAttribute&&(m.a.fromBufferAttribute(this.colorAttribute,l),m.b.fromBufferAttribute(this.colorAttribute,u),m.c.fromBufferAttribute(this.colorAttribute,c),g.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),s.r=g.x,s.g=g.y,s.b=g.z),void 0!==n&&void 0!==this.uvAttribute&&(p.fromBufferAttribute(this.uvAttribute,l),v.fromBufferAttribute(this.uvAttribute,u),f.fromBufferAttribute(this.uvAttribute,c),n.set(0,0).addScaledVector(p,r).addScaledVector(v,a).addScaledVector(f,1-(r+a))),this}}class y{constructor(e,t){n(this,"textureSize"),n(this,"dataTextures"),n(this,"eventEmitter"),n(this,"currentAtlas",null),this.eventEmitter=e,this.textureSize=t,this.dataTextures=new Map,this.updateServiceState("ready")}setTextureSize(e){this.textureSize!==e&&(this.textureSize=e,this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null))}async getDataTexture(e){const t=this.dataTextures.get(e.uuid);if(t)return t;var i,s;const n=function(e,t){const i=new a.BufferGeometry;i.setAttribute("position",new a.BufferAttribute(new Float32Array(e.position),3)),e.normal&&i.setAttribute("normal",new a.BufferAttribute(new Float32Array(e.normal),3));const s=new a.MeshBasicMaterial,n=new a.Mesh(i,s);n.scale.set(e.scale.x,e.scale.y,e.scale.z);const r=new x(n).build(),o=new Float32Array(t*t*4),l=new a.Vector3;for(let a=0;a<t;a++)for(let i=0;i<t;i++){const s=a*t+i;r.sample(l),o[4*s]=l.x*e.scale.x,o[4*s+1]=l.y*e.scale.y,o[4*s+2]=l.z*e.scale.z,o[4*s+3]=.01*(Math.random()-.5)}return o}({position:(i=e).geometry.attributes.position.array,normal:null==(s=i.geometry.attributes.normal)?void 0:s.array,scale:{x:i.scale.x,y:i.scale.y,z:i.scale.z}},this.textureSize),r=u(n,this.textureSize);return r.name=e.name,this.dataTextures.set(e.uuid,r),r}async dispose(){this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null),this.updateServiceState("disposed")}updateServiceState(e){this.eventEmitter.emit("serviceStateUpdated",{type:"data-texture",state:e})}async createSequenceDataTextureAtlas(e,t){this.updateServiceState("loading"),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null);const i=e.length;if(0===i)throw new Error("Mesh array cannot be empty.");const s=t*i,n=t,r=new Float32Array(s*n*4);try{for(let n=0;n<i;n++){const i=e[n],a=(await this.getDataTexture(i)).image.data;for(let e=0;e<t;e++)for(let i=0;i<t;i++){const o=4*(e*t+i),l=4*(e*s+(i+n*t));r[l]=a[o],r[l+1]=a[o+1],r[l+2]=a[o+2],r[l+3]=a[o+3]}}const o=new a.DataTexture(r,s,n,a.RGBAFormat,a.FloatType);return o.needsUpdate=!0,o.name=`atlas-${e.map((e=>e.name)).join("-")}`,this.currentAtlas=o,this.updateServiceState("ready"),o}catch(o){throw this.updateServiceState("error"),o}}}class T{constructor(e){n(this,"size"),n(this,"mesh"),n(this,"matcapMaterial"),n(this,"fallbackGeometry"),n(this,"uniforms"),n(this,"originColor"),n(this,"destinationColor"),n(this,"geometries"),n(this,"uvRefsCache"),n(this,"previousScale"),this.size=e,this.geometries=new Map,this.uvRefsCache=new Map,this.previousScale={x:1,y:1,z:1},this.originColor="grey",this.destinationColor="grey",this.uniforms={uTime:{value:0},uProgress:{value:0},uTexture:{value:null},uVelocity:{value:null},uOriginTexture:{value:null},uDestinationTexture:{value:null}},this.matcapMaterial=new a.ShaderMaterial({uniforms:this.uniforms,vertexShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform sampler2D uVelocity;\nuniform float uTime;\nvarying vec3 vNormal;\nattribute vec2 uvRef;\nvarying vec3 vViewPosition;\n\nvec3 rotate3D(vec3 v, vec3 vel) {\n vec3 pos = v;\n vec3 up = vec3(0, 1, 0);\n vec3 axis = normalize(cross(up, vel));\n float angle = acos(dot(up, normalize(vel)));\n pos = pos * cos(angle) + cross(axis, pos) * sin(angle) + axis * dot(axis, pos) * (1. - cos(angle));\n return pos;\n}\n\nvoid main() {\n vUv = uv;\n vNormal = normal;\n\n vec4 color = texture2D(uTexture, uvRef);\n vec4 velocity = texture2D(uVelocity, uvRef);\n vec3 pos = color.xyz;// apply the texture to the vertex distribution.\n\n vec3 localPosition = position.xyz;\n if (length (velocity.xyz) < 0.0001) {\n velocity.xyz = vec3(0.0, 0.0001, 0.0001);\n }\n localPosition.y *= max(1.0, length(velocity.xyz) * 1000.0);\n localPosition = rotate3D(localPosition, velocity.xyz);\n vNormal = rotate3D(normal, velocity.xyz);\n\n mat4 instanceMat = instanceMatrix;\n instanceMat[3].xyz = pos.xyz;\n\n // unlike the traditional mvMatrix * position, we need to additional multiplication with the instance matrix.\n vec4 modelViewPosition = modelViewMatrix * instanceMat * vec4(localPosition, 1.0);\n\n vViewPosition = - modelViewPosition.xyz;\n\n gl_Position = projectionMatrix * modelViewPosition;\n}\n",fragmentShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\n\nuniform sampler2D uOriginTexture;\nuniform sampler2D uDestinationTexture;\n\nuniform float uProgress;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvoid main() {\n vec3 viewDir = normalize( vViewPosition );\n vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n vec3 y = cross( viewDir, x );\n vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks\n\n vec4 sourceMatcap = texture2D( uOriginTexture, uv );\n vec4 targetMatcap = texture2D( uDestinationTexture, uv );\n\n vec4 matcap = mix(sourceMatcap, targetMatcap, uProgress);\n gl_FragColor = matcap;\n}\n"}),this.setOriginColor(this.originColor),this.setDestinationColor(this.destinationColor),this.fallbackGeometry=new a.BoxGeometry(.001,.001,.001),this.mesh=this.createInstancedMesh(e,this.fallbackGeometry,this.matcapMaterial)}getMesh(){return this.mesh}update(e){const t=this.mesh.material;(t instanceof a.ShaderMaterial||t instanceof a.RawShaderMaterial)&&(t.uniforms.uTime.value=e)}setOriginMatcap(e){this.disposeSolidColorOriginTexture(),this.matcapMaterial.uniforms.uOriginTexture.value=e}setDestinationMatcap(e){this.disposeSolidColorDestinationTexture(),this.matcapMaterial.uniforms.uDestinationTexture.value=e}setProgress(e){e=Math.max(0,e),e=Math.min(1,e),this.matcapMaterial.uniforms.uProgress.value=e}setGeometrySize(e){this.mesh.geometry.scale(1/this.previousScale.x,1/this.previousScale.y,1/this.previousScale.z),this.mesh.geometry.scale(e.x,e.y,e.z),this.previousScale=e}useMatcapMaterial(){this.mesh.material=this.matcapMaterial}useGeometry(e){const t=this.geometries.get(e);t&&(this.mesh.geometry=t)}updateVelocityTexture(e){this.matcapMaterial.uniforms.uVelocity.value=e}updatePositionTexture(e){this.matcapMaterial.uniforms.uTexture.value=e}resize(e){if(this.size===e)return{current:this.mesh,previous:this.mesh};this.size=e;const t=this.mesh;return this.mesh=this.createInstancedMesh(e,t.geometry,t.material),{current:this.mesh,previous:t}}dispose(){this.mesh.dispose(),this.geometries.forEach((e=>e.dispose())),this.disposeSolidColorOriginTexture(),this.disposeSolidColorDestinationTexture(),this.matcapMaterial.dispose(),this.uvRefsCache.clear(),this.geometries.clear()}registerGeometry(e,t){const i=this.geometries.get(e);if(i&&i===t)return;const s=this.createUVRefs(this.size);t.setAttribute("uvRef",s),this.geometries.set(e,t),this.mesh.geometry===i&&(this.mesh.geometry=t),null==i||i.dispose()}setOriginColor(e){this.disposeSolidColorOriginTexture(),this.originColor=e,this.uniforms.uOriginTexture.value=this.createSolidColorDataTexture(e)}setDestinationColor(e){this.disposeSolidColorDestinationTexture(),this.destinationColor=e,this.uniforms.uDestinationTexture.value=this.createSolidColorDataTexture(e)}createUVRefs(e){const t=this.uvRefsCache.get(e);if(t)return t;const i=new Float32Array(e*e*2);for(let n=0;n<e;n++)for(let t=0;t<e;t++){const s=n*e+t;i[2*s]=t/(e-1),i[2*s+1]=n/(e-1)}const s=new a.InstancedBufferAttribute(i,2);return this.uvRefsCache.set(e,s),s}createInstancedMesh(e,t,i){(t=t||this.fallbackGeometry).setAttribute("uvRef",this.createUVRefs(e));const s=e*e;return new a.InstancedMesh(t,i,s)}createSolidColorDataTexture(e,t=16){const i=new a.Color(e),s=t,n=t,r=new Uint8Array(s*n*4),o=Math.floor(255*i.r),l=Math.floor(255*i.g),u=Math.floor(255*i.b);for(let a=0;a<s*n;a++){const e=4*a;r[e]=o,r[e+1]=l,r[e+2]=u,r[e+3]=255}const c=new a.DataTexture(r,s,n,a.RGBAFormat);return c.type=a.UnsignedByteType,c.wrapS=a.RepeatWrapping,c.wrapT=a.RepeatWrapping,c.minFilter=a.NearestFilter,c.magFilter=a.NearestFilter,c.needsUpdate=!0,c}disposeSolidColorOriginTexture(){this.originColor&&(this.originColor=null,this.uniforms.uOriginTexture.value&&this.uniforms.uOriginTexture.value.dispose())}disposeSolidColorDestinationTexture(){this.destinationColor&&(this.destinationColor=null,this.uniforms.uDestinationTexture.value&&this.uniforms.uDestinationTexture.value.dispose())}}class S{constructor(e,t){n(this,"active",!0),n(this,"raycaster",new a.Raycaster),n(this,"mousePosition",new a.Vector2),n(this,"camera"),n(this,"meshSequenceGeometries",[]),n(this,"meshSequenceUUIDs",[]),n(this,"overallProgress",0),n(this,"intersectionMesh",new a.Mesh),n(this,"geometryNeedsUpdate"),n(this,"eventEmitter"),n(this,"blendedGeometry"),n(this,"intersection"),this.camera=t,this.eventEmitter=e,this.geometryNeedsUpdate=!0}setActive(e){this.active=e,e||(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}}))}getIntersectionMesh(){return this.intersectionMesh}setCamera(e){this.camera=e}setMeshSequence(e){this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],e&&0!==e.length?(e.forEach((e=>{if(e&&e.geometry){const t=e.geometry.clone();t.applyMatrix4(e.matrixWorld),this.meshSequenceGeometries.push(t),this.meshSequenceUUIDs.push(e.uuid)}else console.warn("Invalid mesh provided to IntersectionService sequence.")})),this.geometryNeedsUpdate=!0):this.geometryNeedsUpdate=!0}setOverallProgress(e){const t=a.MathUtils.clamp(e,0,1);this.overallProgress!==t&&(this.overallProgress=t,this.geometryNeedsUpdate=!0)}setPointerPosition(e){e&&this.mousePosition.copy(e)}calculate(e){var t,i,s;if(!this.active||!this.camera||0===this.meshSequenceGeometries.length)return void(this.intersection&&(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}})));let n;this.geometryNeedsUpdate&&(this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),this.blendedGeometry=this.getBlendedGeometry(),this.geometryNeedsUpdate=!1,this.blendedGeometry?this.intersectionMesh.geometry!==this.blendedGeometry&&(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry):(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=new a.BufferGeometry)),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.blendedGeometry&&this.blendedGeometry.attributes.position&&(n=this.getFirstIntersection(this.camera,this.intersectionMesh));if((null==(t=this.intersection)?void 0:t.x)!==(null==n?void 0:n.x)||(null==(i=this.intersection)?void 0:i.y)!==(null==n?void 0:n.y)||(null==(s=this.intersection)?void 0:s.z)!==(null==n?void 0:n.z)||this.intersection&&!n||!this.intersection&&n)if(this.intersection=n,this.intersection){const t=new a.Vector3(this.intersection.x,this.intersection.y,this.intersection.z),i=e.worldToLocal(t.clone());this.intersection.set(i.x,i.y,i.z,1),this.eventEmitter.emit("interactionPositionUpdated",{position:this.intersection})}else this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}});return this.intersection}dispose(){var e;this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),null==(e=this.intersectionMesh.geometry)||e.dispose()}updateIntersectionMesh(e){this.blendedGeometry&&this.blendedGeometry.uuid!==this.intersectionMesh.geometry.uuid&&(this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry),this.intersectionMesh.matrix.copy(e.matrixWorld),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.intersectionMesh.matrixAutoUpdate=!1,this.intersectionMesh.updateMatrixWorld(!0)}getFirstIntersection(e,t){this.raycaster.setFromCamera(this.mousePosition,e);const i=this.raycaster.intersectObject(t,!1);if(i.length>0&&i[0].point){const e=i[0].point;return new a.Vector4(e.x,e.y,e.z,1)}}getBlendedGeometry(){const e=this.meshSequenceGeometries.length;if(0===e)return;if(1===e)return this.meshSequenceGeometries[0];const t=e-1,i=1/t,s=this.overallProgress*t;let n=Math.floor(s),r=n+1;n=a.MathUtils.clamp(n,0,t),r=a.MathUtils.clamp(r,0,t);let o=0;i>0&&(o=s-n),this.overallProgress>=1&&(n=t,r=t,o=1),o=a.MathUtils.clamp(o,0,1);const l=this.meshSequenceGeometries[n],u=this.meshSequenceGeometries[r];return l&&u?n===r?l:this.blendGeometry(l,u,o):(console.error("IntersectionService: Invalid geometries found for blending at indices",n,r),this.meshSequenceGeometries[0])}blendGeometry(e,t,i){const s=new a.BufferGeometry,n=e.attributes.position.array,r=t.attributes.position.array,o=new Float32Array(n.length);for(let l=0;l<n.length;l+=3){const e=new a.Vector3(n[l],n[l+1],n[l+2]),t=new a.Vector3(r[l],r[l+1],r[l+2]),s=(new a.Vector3).lerpVectors(e,t,i);o[l]=s.x,o[l+1]=s.y,o[l+2]=s.z}return s.setAttribute("position",new a.BufferAttribute(o,3)),e.attributes.normal&&s.setAttribute("normal",e.attributes.normal.clone()),e.attributes.uv&&s.setAttribute("uv",e.attributes.uv.clone()),e.index&&s.setIndex(e.index.clone()),s}}const M=new t.OrthographicCamera(-1,1,1,-1,0,1);class P extends t.BufferGeometry{constructor(){super(),this.setAttribute("position",new t.Float32BufferAttribute([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new t.Float32BufferAttribute([0,2,0,0,2,0],2))}}const w=new P;class A{constructor(e){this._mesh=new t.Mesh(w,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,M)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class b{constructor(e,i,s){this.variables=[],this.currentTextureIndex=0;let n=t.FloatType;const r={passThruTexture:{value:null}},a=u("uniform sampler2D passThruTexture;\n\nvoid main() {\n\n\tvec2 uv = gl_FragCoord.xy / resolution.xy;\n\n\tgl_FragColor = texture2D( passThruTexture, uv );\n\n}\n",r),o=new A(a);function l(t){t.defines.resolution="vec2( "+e.toFixed(1)+", "+i.toFixed(1)+" )"}function u(e,i){i=i||{};const s=new t.ShaderMaterial({name:"GPUComputationShader",uniforms:i,vertexShader:"void main()\t{\n\n\tgl_Position = vec4( position, 1.0 );\n\n}\n",fragmentShader:e});return l(s),s}this.setDataType=function(e){return n=e,this},this.addVariable=function(e,i,s){const n={name:e,initialValueTexture:s,material:this.createShaderMaterial(i),dependencies:null,renderTargets:[],wrapS:null,wrapT:null,minFilter:t.NearestFilter,magFilter:t.NearestFilter};return this.variables.push(n),n},this.setVariableDependencies=function(e,t){e.dependencies=t},this.init=function(){if(0===s.capabilities.maxVertexTextures)return"No support for vertex shader textures.";for(let t=0;t<this.variables.length;t++){const s=this.variables[t];s.renderTargets[0]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),s.renderTargets[1]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),this.renderTexture(s.initialValueTexture,s.renderTargets[0]),this.renderTexture(s.initialValueTexture,s.renderTargets[1]);const n=s.material,r=n.uniforms;if(null!==s.dependencies)for(let e=0;e<s.dependencies.length;e++){const t=s.dependencies[e];if(t.name!==s.name){let e=!1;for(let i=0;i<this.variables.length;i++)if(t.name===this.variables[i].name){e=!0;break}if(!e)return"Variable dependency not found. Variable="+s.name+", dependency="+t.name}r[t.name]={value:null},n.fragmentShader="\nuniform sampler2D "+t.name+";\n"+n.fragmentShader}}return this.currentTextureIndex=0,null},this.compute=function(){const e=this.currentTextureIndex,t=0===this.currentTextureIndex?1:0;for(let i=0,s=this.variables.length;i<s;i++){const s=this.variables[i];if(null!==s.dependencies){const t=s.material.uniforms;for(let i=0,n=s.dependencies.length;i<n;i++){const n=s.dependencies[i];t[n.name].value=n.renderTargets[e].texture}}this.doRenderTarget(s.material,s.renderTargets[t])}this.currentTextureIndex=t},this.getCurrentRenderTarget=function(e){return e.renderTargets[this.currentTextureIndex]},this.getAlternateRenderTarget=function(e){return e.renderTargets[0===this.currentTextureIndex?1:0]},this.dispose=function(){o.dispose();const e=this.variables;for(let t=0;t<e.length;t++){const i=e[t];i.initialValueTexture&&i.initialValueTexture.dispose();const s=i.renderTargets;for(let e=0;e<s.length;e++){s[e].dispose()}}},this.addResolutionDefine=l,this.createShaderMaterial=u,this.createRenderTarget=function(s,r,a,o,l,u){s=s||e,r=r||i,a=a||t.ClampToEdgeWrapping,o=o||t.ClampToEdgeWrapping,l=l||t.NearestFilter,u=u||t.NearestFilter;return new t.WebGLRenderTarget(s,r,{wrapS:a,wrapT:o,minFilter:l,magFilter:u,format:t.RGBAFormat,type:n,depthBuffer:!1})},this.createTexture=function(){const s=new Float32Array(e*i*4),n=new t.DataTexture(s,e,i,t.RGBAFormat,t.FloatType);return n.needsUpdate=!0,n},this.renderTexture=function(e,t){r.passThruTexture.value=e,this.doRenderTarget(a,t),r.passThruTexture.value=null},this.doRenderTarget=function(e,t){const i=s.getRenderTarget(),n=s.xr.enabled,r=s.shadowMap.autoUpdate;s.xr.enabled=!1,s.shadowMap.autoUpdate=!1,o.material=e,s.setRenderTarget(t),o.render(s),o.material=a,s.xr.enabled=n,s.shadowMap.autoUpdate=r,s.setRenderTarget(i)}}}class V{constructor(e,t,i){n(this,"gpuComputationRenderer"),n(this,"webGLRenderer"),n(this,"velocityVar"),n(this,"positionVar"),n(this,"initialPositionDataTexture"),n(this,"initialVelocityDataTexture"),n(this,"positionAtlasTexture",null),n(this,"interactionPosition"),n(this,"lastKnownPositionDataTexture"),n(this,"lastKnownVelocityDataTexture"),this.webGLRenderer=t,this.gpuComputationRenderer=new b(e,e,this.webGLRenderer),!t.capabilities.isWebGL2&&t.extensions.get("OES_texture_float")?this.gpuComputationRenderer.setDataType(a.FloatType):t.capabilities.isWebGL2||this.gpuComputationRenderer.setDataType(a.HalfFloatType),this.initialPositionDataTexture=i??function(e){const t=new Float32Array(e*e*4);for(let i=0;i<e;i++)for(let s=0;s<e;s++){const n=i*e+s;let r=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1),o=Math.sin(a)*Math.cos(r),l=Math.sin(a)*Math.sin(r),u=Math.cos(a);t[4*n]=o,t[4*n+1]=l,t[4*n+2]=u,t[4*n+3]=.01*(Math.random()-.5)}return u(t,e)}(e),this.initialVelocityDataTexture=function(e){return u(new Float32Array(4*e*e),e)}(e),this.interactionPosition=new a.Vector4(0,0,0,0),this.velocityVar=this.gpuComputationRenderer.addVariable("uCurrentVelocity",'\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform float uMaxRepelDistance;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress;\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function (same as in position shader)\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize;\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex), uv.y);\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n float offset = rand(uv);\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas (same logic as position shader) ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n int indexA = int(floor(scaledProgress));\n int indexB = min(indexA + 1, uNumMeshes - 1);\n indexA = min(indexA, uNumMeshes - 1);\n float localProgress = fract(scaledProgress);\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0;\n }\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n vec3 finalVelocity = currentVelocity * 0.9; // Dampening\n\n // Particle traction force towards target (influences velocity)\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n if (dist > 0.01) {\n // Add force proportional to distance and traction setting\n finalVelocity += direction * dist * 0.01 * uTractionForce; // Adjust multiplier as needed\n }\n\n // Mouse repel force\n if (uInteractionPosition.w > 0.0) { // Check if interaction is active (w component)\n float pointerDistance = distance(currentPosition, uInteractionPosition.xyz);\n if (pointerDistance < uMaxRepelDistance) {\n float mouseRepelModifier = smoothstep(uMaxRepelDistance, 0.0, pointerDistance); // Smoother falloff\n vec3 repelDirection = normalize(currentPosition - uInteractionPosition.xyz);\n // Apply force based on proximity and interaction strength (w)\n finalVelocity += repelDirection * mouseRepelModifier * uInteractionPosition.w * 0.01; // Adjust multiplier\n }\n }\n\n // Optional: Reset position if particle "dies" and respawns (lifespan logic)\n float lifespan = 20.0;\n float age = mod(uTime * 0.1 + lifespan * offset, lifespan); // Adjust time scale\n if (age < 0.05) { // Small window for reset\n finalVelocity = vec3(0.0); // Reset velocity on respawn\n // Note: Resetting position directly here might cause jumps.\n // It\'s often better handled in the position shader or by ensuring\n // strong attraction force when dist is large.\n }\n\n\n gl_FragColor = vec4(finalVelocity, 1.0);\n}\n',this.initialVelocityDataTexture),this.positionVar=this.gpuComputationRenderer.addVariable("uCurrentPosition","\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress; // (0.0 to 1.0)\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function to get position from atlas\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize; // Assuming height is single texture size\n\n // Calculate UV within the specific mesh's section of the atlas\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(\n uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex),\n uv.y // Assuming vertical layout doesn't change y\n );\n\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n // GPGPU UV calculation\n vec2 uv = gl_FragCoord.xy / resolution.xy; // resolution is the size of the *output* texture (e.g., 256x256)\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n\n int indexA = int(floor(scaledProgress));\n // Clamp indexB to avoid going out of bounds\n int indexB = min(indexA + 1, uNumMeshes - 1);\n\n // Ensure indexA is also within bounds (important if uOverallProgress is exactly 1.0)\n indexA = min(indexA, uNumMeshes - 1);\n\n\n float localProgress = fract(scaledProgress);\n\n // Handle edge case where progress is exactly 1.0\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0; // or 0.0 depending on how you want to handle it\n }\n\n\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n // Particle attraction to target position\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n\n vec3 finalPosition = currentPosition;\n\n // Apply attraction force (simplified mix)\n if (dist > 0.01) { // Only apply if significantly far\n finalPosition = mix(currentPosition, targetPosition, 0.1 * uTractionForce);\n }\n\n finalPosition += currentVelocity;\n gl_FragColor = vec4(finalPosition, 1.0);\n}\n",this.initialPositionDataTexture),this.velocityVar.material.uniforms.uTime={value:0},this.velocityVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.velocityVar.material.uniforms.uCurrentPosition={value:null},this.velocityVar.material.uniforms.uTractionForce={value:.1},this.velocityVar.material.uniforms.uMaxRepelDistance={value:.3},this.velocityVar.material.uniforms.uPositionAtlas={value:null},this.velocityVar.material.uniforms.uOverallProgress={value:0},this.velocityVar.material.uniforms.uNumMeshes={value:1},this.velocityVar.material.uniforms.uSingleTextureSize={value:e},this.positionVar.material.uniforms.uTime={value:0},this.positionVar.material.uniforms.uTractionForce={value:.1},this.positionVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.positionVar.material.uniforms.uCurrentPosition={value:null},this.positionVar.material.uniforms.uCurrentVelocity={value:null},this.positionVar.material.uniforms.uPositionAtlas={value:null},this.positionVar.material.uniforms.uOverallProgress={value:0},this.positionVar.material.uniforms.uNumMeshes={value:1},this.positionVar.material.uniforms.uSingleTextureSize={value:e},this.gpuComputationRenderer.setVariableDependencies(this.positionVar,[this.positionVar,this.velocityVar]),this.gpuComputationRenderer.setVariableDependencies(this.velocityVar,[this.velocityVar,this.positionVar]);const s=this.gpuComputationRenderer.init();if(null!==s)throw new Error("Failed to initialize SimulationRenderer: "+s);this.positionVar.material.uniforms.uPositionAtlas.value=this.initialPositionDataTexture,this.positionVar.material.uniforms.uNumMeshes.value=1,this.velocityVar.material.uniforms.uNumMeshes.value=1,this.positionVar.material.uniforms.uSingleTextureSize.value=e,this.velocityVar.material.uniforms.uSingleTextureSize.value=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t&&e.dataTexture.image.height===e.singleTextureSize||console.error(`SimulationRenderer: Atlas texture dimension mismatch! Expected ${t}x${e.singleTextureSize}, Got ${e.dataTexture.image.width}x${e.dataTexture.image.height}`),this.positionAtlasTexture=e.dataTexture;const i=e.numMeshes>0?e.numMeshes:1;this.positionVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.positionVar.material.uniforms.uNumMeshes.value=i,this.positionVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.velocityVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.velocityVar.material.uniforms.uNumMeshes.value=i,this.velocityVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setOverallProgress(e){const t=h(e,0,1);this.positionVar.material.uniforms.uOverallProgress.value=t,this.velocityVar.material.uniforms.uOverallProgress.value=t}setMaxRepelDistance(e){this.velocityVar.material.uniforms.uMaxRepelDistance.value=e}setVelocityTractionForce(e){this.velocityVar.material.uniforms.uTractionForce.value=e}setPositionalTractionForce(e){this.positionVar.material.uniforms.uTractionForce.value=e}setInteractionPosition(e){this.interactionPosition.copy(e)}dispose(){var e,t;this.gpuComputationRenderer.dispose(),null==(e=this.initialPositionDataTexture)||e.dispose(),null==(t=this.initialVelocityDataTexture)||t.dispose(),this.positionAtlasTexture=null}compute(e){this.velocityVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.gpuComputationRenderer.compute(),this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}}class R{constructor(e,t,i){n(this,"state"),n(this,"textureSize"),n(this,"overallProgress"),n(this,"velocityTractionForce"),n(this,"positionalTractionForce"),n(this,"simulationRenderer"),n(this,"webGLRenderer"),n(this,"eventEmitter"),n(this,"currentAtlasEntry",null),n(this,"lastKnownVelocityDataTexture"),n(this,"lastKnownPositionDataTexture"),this.eventEmitter=e,this.webGLRenderer=i,this.textureSize=t,this.overallProgress=0,this.velocityTractionForce=.1,this.positionalTractionForce=.1,this.updateServiceState("initializing"),this.simulationRenderer=new V(this.textureSize,this.webGLRenderer),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture(),this.updateServiceState("ready")}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t?(this.currentAtlasEntry=e,this.simulationRenderer.setPositionAtlas(e)):this.eventEmitter.emit("invalidRequest",{message:"Atlas texture width mismatch."})}setOverallProgress(e){this.overallProgress=e,this.simulationRenderer.setOverallProgress(this.overallProgress)}setTextureSize(e){this.updateServiceState("initializing"),this.simulationRenderer.dispose(),this.textureSize=e,this.simulationRenderer=new V(e,this.webGLRenderer),this.updateServiceState("ready")}setVelocityTractionForce(e){this.velocityTractionForce=e,this.simulationRenderer.setVelocityTractionForce(this.velocityTractionForce)}setPositionalTractionForce(e){this.positionalTractionForce=e,this.simulationRenderer.setPositionalTractionForce(this.positionalTractionForce)}compute(e){"ready"===this.state&&(this.simulationRenderer.compute(e),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture())}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}dispose(){this.updateServiceState("disposed"),this.simulationRenderer.dispose(),this.currentAtlasEntry=null}updateServiceState(e){this.state=e,this.eventEmitter.emit("serviceStateUpdated",{type:"simulation",state:e})}setInteractionPosition(e){this.simulationRenderer.setInteractionPosition(e)}setMaxRepelDistance(e){this.simulationRenderer.setMaxRepelDistance(e)}}class C{constructor(){n(this,"execStatus",new Map)}get(e){const t=this.execStatus.get(e);return t||(this.execStatus.set(e,"idle"),"idle")}set(e,t){this.execStatus.set(e,t)}}class D{constructor(e){n(this,"eventEmitter"),n(this,"transitions",new Map),n(this,"execStatus"),n(this,"ongoingTransitions",new Map),this.eventEmitter=e,this.execStatus=new C,this.eventEmitter.on("transitionCancelled",this.handleTransitionCancelledEvent.bind(this))}enqueue(e,t,i={}){const s={...t,...i,cancelled:!1,duration:.001*t.duration};this.getQueue(e).push(s)}compute(e){this.transitions.forEach(((t,i)=>{var s;if(t.length&&!this.ongoingTransitions.has(i)){const n=t.shift();n&&(this.ongoingTransitions.set(i,{...n,startTime:e}),null==(s=n.onTransitionBegin)||s.call(n))}})),this.ongoingTransitions.forEach(((t,i)=>{var s,n,r;if(t.cancelled)return null==(s=t.onTransitionCancelled)||s.call(t),void this.ongoingTransitions.delete(i);const{startTime:a,duration:o,easing:l}=t,u=e-a,c=h(l(Math.min(1,u/o)),0,1);this.emitTransitionProgress(i,c),null==(n=t.onTransitionProgress)||n.call(t,c),c>=1&&(this.emitTransitionFinished(i),null==(r=t.onTransitionFinished)||r.call(t),this.ongoingTransitions.delete(i))}))}getQueue(e){const t=this.transitions.get(e);return t||(this.transitions.set(e,[]),this.transitions.get(e)??[])}handleTransitionCancelledEvent({type:e}){var t;const i=this.getQueue(e);for(;i.length;)i.pop();const s=this.ongoingTransitions.get(e);s&&(s.cancelled=!0,null==(t=s.onTransitionCancelled)||t.call(s))}emitTransitionProgress(e,t){this.eventEmitter.emit("transitionProgressed",{type:e,progress:t})}emitTransitionFinished(e){this.eventEmitter.emit("transitionFinished",{type:e})}}return e.ParticlesEngine=class{constructor(e){n(this,"simulationRendererService"),n(this,"renderer"),n(this,"scene"),n(this,"serviceStates"),n(this,"assetService"),n(this,"dataTextureManager"),n(this,"instancedMeshManager"),n(this,"transitionService"),n(this,"engineState"),n(this,"intersectionService"),n(this,"meshSequenceAtlasTexture",null),n(this,"eventEmitter");const{scene:t,renderer:i,camera:s,textureSize:r,useIntersection:a=!0}=e;this.eventEmitter=new l,this.serviceStates=this.getInitialServiceStates(),this.eventEmitter.on("serviceStateUpdated",this.handleServiceStateUpdated.bind(this)),this.scene=t,this.renderer=i,this.engineState=this.initialEngineState(e),this.assetService=new d(this.eventEmitter),this.transitionService=new D(this.eventEmitter),this.dataTextureManager=new y(this.eventEmitter,r),this.simulationRendererService=new R(this.eventEmitter,r,this.renderer),this.instancedMeshManager=new T(r),this.instancedMeshManager.useMatcapMaterial(),this.scene.add(this.instancedMeshManager.getMesh()),this.intersectionService=new S(this.eventEmitter,s),a||this.intersectionService.setActive(!1),this.eventEmitter.on("interactionPositionUpdated",this.handleInteractionPositionUpdated.bind(this))}render(e){const t=e/1e3;this.transitionService.compute(t),this.intersectionService.calculate(this.instancedMeshManager.getMesh()),this.simulationRendererService.compute(t),this.instancedMeshManager.update(t),this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture()),this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture())}setOriginMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.originMatcapID=e,this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(e))}setDestinationMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.destinationMatcapID=e,this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(e))}setOriginColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setOriginColor(e)}setDestinationColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setDestinationColor(e)}setOriginTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setOriginMatcap(e):this.setOriginColor(e)}setDestinationTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setDestinationMatcap(e):this.setDestinationColor(e)}setMatcapProgress(e,t=!1){const i=h(e,0,1);t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.matcapTransitionProgress=i,this.instancedMeshManager.setProgress(i)}async setTextureSize(e){this.engineState.textureSize!==e&&(this.engineState.textureSize=e,this.dataTextureManager.setTextureSize(e),this.simulationRendererService.setTextureSize(e),this.instancedMeshManager.resize(e),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce),this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce),this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setOverallProgress(this.engineState.overallProgress),this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID)),this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID)),this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress),this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale))}registerMesh(e,t){this.assetService.register(e,t)}registerMatcap(e,t){this.assetService.register(e,t)}async fetchAndRegisterMesh(e,t){return await this.assetService.loadMeshAsync(e,t)}async fetchAndRegisterMatcap(e,t){return await this.assetService.loadTextureAsync(e,t)}useIntersect(e){this.intersectionService.setActive(e),this.engineState.useIntersect=e,e||(this.engineState.pointerPosition={x:-99999999,y:-99999999},this.simulationRendererService.setInteractionPosition({x:0,y:0,z:0,w:0}))}setPointerPosition(e){this.engineState.useIntersect&&(this.engineState.pointerPosition=e,this.intersectionService.setPointerPosition(e))}setGeometrySize(e){this.engineState.instanceGeometryScale=e,this.instancedMeshManager.setGeometrySize(e)}setVelocityTractionForce(e){this.engineState.velocityTractionForce=e,this.simulationRendererService.setVelocityTractionForce(e)}setPositionalTractionForce(e){this.engineState.positionalTractionForce=e,this.simulationRendererService.setPositionalTractionForce(e)}setMaxRepelDistance(e){this.engineState.maxRepelDistance=e,this.simulationRendererService.setMaxRepelDistance(e)}async setMeshSequence(e){if(!e||e.length<1)return this.eventEmitter.emit("invalidRequest",{message:"Mesh sequence must contain at least one mesh ID."}),this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=e,this.engineState.overallProgress=0;const t=e.map((e=>this.assetService.getMesh(e))).filter((e=>null!==e));if(t.length!==e.length){const i=e.filter((e=>!this.assetService.getMesh(e)));if(console.warn(`Could not find meshes for IDs: ${i.join(", ")}. Proceeding with ${t.length} found meshes.`),this.eventEmitter.emit("invalidRequest",{message:`Could not find meshes for IDs: ${i.join(", ")}`}),t.length<1)return this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=t.map((e=>e.name))}try{this.meshSequenceAtlasTexture=await this.dataTextureManager.createSequenceDataTextureAtlas(t,this.engineState.textureSize),this.simulationRendererService.setPositionAtlas({dataTexture:this.meshSequenceAtlasTexture,textureSize:this.engineState.textureSize,numMeshes:this.engineState.meshSequence.length,singleTextureSize:this.engineState.textureSize}),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setMeshSequence(t),this.intersectionService.setOverallProgress(this.engineState.overallProgress)}catch(i){console.error("Failed during mesh sequence setup:",i),this.meshSequenceAtlasTexture=null}}setOverallProgress(e,t=!0){t&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const i=h(e,0,1);this.engineState.overallProgress=i,this.simulationRendererService.setOverallProgress(i),this.intersectionService.setOverallProgress(i)}scheduleMatcapTransition(e,t,i=o,s=1e3,n=!1,r={}){n&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:i,duration:s},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginMatcap(e,!1),this.setDestinationMatcap(t,!1),this.setMatcapProgress(0,!1),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1,!1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:r.onTransitionCancelled})}scheduleTextureTransition(e,t,i={}){const s=(null==i?void 0:i.easing)??o,n=(null==i?void 0:i.duration)??1e3,r={onTransitionBegin:null==i?void 0:i.onTransitionBegin,onTransitionProgress:null==i?void 0:i.onTransitionProgress,onTransitionFinished:null==i?void 0:i.onTransitionFinished,onTransitionCancelled:null==i?void 0:i.onTransitionCancelled};(null==i?void 0:i.override)&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:s,duration:n},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginTexture(e),this.setDestinationTexture(t),this.setMatcapProgress(0),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:()=>{var e;null==(e=r.onTransitionCancelled)||e.call(r)}})}scheduleMeshSequenceTransition(e,t=1e3,i=o,s={},n=!0){n&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const r=this.engineState.overallProgress,a=e-r,l={duration:t,easing:i},u={...s,onTransitionProgress:e=>{var t;const i=r+a*e;this.setOverallProgress(i,!1),null==(t=s.onTransitionProgress)||t.call(s,i)},onTransitionBegin:s.onTransitionBegin,onTransitionFinished:()=>{var t;this.setOverallProgress(e,!1),null==(t=s.onTransitionFinished)||t.call(s)},onTransitionCancelled:s.onTransitionCancelled};this.transitionService.enqueue("mesh-sequence",l,u)}handleServiceStateUpdated({type:e,state:t}){this.serviceStates[e]=t}getObject(){return this.instancedMeshManager.getMesh()}getMeshIDs(){return this.assetService.getMeshIDs()}getMatcapIDs(){return this.assetService.getTextureIDs()}getMeshes(){return this.assetService.getMeshes()}getTextures(){return this.assetService.getTextures()}getTextureSize(){return this.engineState.textureSize}getUseIntersect(){return this.engineState.useIntersect}getEngineStateSnapshot(){return{...this.engineState}}dispose(){var e,t,i,s,n,r;this.scene&&this.instancedMeshManager&&this.scene.remove(this.instancedMeshManager.getMesh()),null==(e=this.simulationRendererService)||e.dispose(),null==(t=this.instancedMeshManager)||t.dispose(),null==(i=this.intersectionService)||i.dispose(),null==(s=this.assetService)||s.dispose(),null==(n=this.dataTextureManager)||n.dispose(),null==(r=this.eventEmitter)||r.dispose()}initialEngineState(e){return{textureSize:e.textureSize,meshSequence:[],overallProgress:0,originMatcapID:"",destinationMatcapID:"",matcapTransitionProgress:0,velocityTractionForce:.1,positionalTractionForce:.1,maxRepelDistance:.3,pointerPosition:{x:0,y:0},instanceGeometryScale:{x:1,y:1,z:1},useIntersect:e.useIntersection??!0}}getInitialServiceStates(){return{"data-texture":"created","instanced-mesh":"created",matcap:"created",simulation:"created",asset:"created"}}handleInteractionPositionUpdated({position:e}){this.simulationRendererService.setInteractionPosition(e)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({},THREE,three-stdlib);
|
|
1
|
+
var ionian=function(e,t,i){"use strict";var s=Object.defineProperty,n=(e,t,i)=>((e,t,i)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i)(e,"symbol"!=typeof t?t+"":t,i);function r(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const s=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,s.get?s:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const a=r(t),o=e=>e;class l{constructor(){var e;n(this,"emitter",{all:e=e||new Map,on:function(t,i){var s=e.get(t);s?s.push(i):e.set(t,[i])},off:function(t,i){var s=e.get(t);s&&(i?s.splice(s.indexOf(i)>>>0,1):e.set(t,[]))},emit:function(t,i){var s=e.get(t);s&&s.slice().map((function(e){e(i)})),(s=e.get("*"))&&s.slice().map((function(e){e(t,i)}))}})}emit(e,t){this.emitter.emit(e,t)}off(e,t){this.emitter.off(e,t)}on(e,t){this.emitter.on(e,t)}once(e,t){this.emitter.on(e,(i=>{this.emitter.off(e,t),t(i)}))}dispose(){this.emitter.all.clear()}}function u(e,t){const i=new a.DataTexture(e,t,t,a.RGBAFormat,a.FloatType);return i.needsUpdate=!0,i}function c(e){e.geometry.dispose(),e.material instanceof a.Material?e.material.dispose():e.material.forEach((e=>e.dispose()))}function h(e,t,i){return e=Math.min(e,i),e=Math.max(e,t)}class d{constructor(e){n(this,"serviceState","created"),n(this,"eventEmitter"),n(this,"meshes",new Map),n(this,"textures",new Map),n(this,"gltfLoader",new i.GLTFLoader),n(this,"textureLoader",new a.TextureLoader),n(this,"dracoLoader",new i.DRACOLoader),n(this,"solidColorTexture",new a.DataTexture(new Uint8Array([127,127,127,255]),1,1,a.RGBAFormat)),this.eventEmitter=e,this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/"),this.gltfLoader.setDRACOLoader(this.dracoLoader),this.updateServiceState("ready")}register(e,t){if(t.name=e,t instanceof a.Mesh){const i=this.meshes.get(e);i&&c(i),this.meshes.set(e,t)}else{const i=this.textures.get(e);i&&i.dispose(),this.textures.set(e,t)}this.eventEmitter.emit("assetRegistered",{id:e})}setSolidColor(e){this.changeColor(e)}getSolidColorTexture(){return this.solidColorTexture}getMesh(e){return this.meshes.get(e)??null}getMatcap(e){const t=this.textures.get(e);return t||this.eventEmitter.emit("invalidRequest",{message:`texture with id "${e}" not found. using solid color texture instead...`}),t??this.solidColorTexture}getMeshIDs(){return Array.from(this.meshes.keys())}getTextureIDs(){return Array.from(this.textures.keys())}getMeshes(){return Array.from(this.meshes.values())}getTextures(){return Array.from(this.textures.values())}hasMatcap(e){return this.textures.has(e)}async loadMeshAsync(e,t,i={}){const s=await this.gltfLoader.loadAsync(t);try{if(i.meshName){const t=s.scene.getObjectByName(i.meshName);return this.register(e,t),t}{const t=s.scene.children[0];return this.register(e,t),t}}catch(n){return this.eventEmitter.emit("invalidRequest",{message:`failed to load mesh: ${e}. ${n}`}),null}}async loadTextureAsync(e,t){try{const i=await this.textureLoader.loadAsync(t);return this.register(e,i),i}catch(i){return this.eventEmitter.emit("invalidRequest",{message:`failed to load texture: ${e}. ${i}`}),null}}dispose(){this.updateServiceState("disposed"),this.meshes.forEach((e=>c(e))),this.meshes.clear(),this.textures.forEach((e=>e.dispose())),this.textures.clear()}changeColor(e){const t=new a.Color(e);this.solidColorTexture=new a.DataTexture(new Uint8Array([t.r,t.g,t.b,255]),1,1,a.RGBAFormat),this.solidColorTexture.needsUpdate=!0}updateServiceState(e){this.serviceState=e,this.eventEmitter.emit("serviceStateUpdated",{type:"asset",state:e})}}const m=new t.Triangle,g=new t.Vector3,p=new t.Vector2,v=new t.Vector2,f=new t.Vector2;class x{constructor(e){this.geometry=e.geometry,this.randomFunction=Math.random,this.indexAttribute=this.geometry.index,this.positionAttribute=this.geometry.getAttribute("position"),this.normalAttribute=this.geometry.getAttribute("normal"),this.colorAttribute=this.geometry.getAttribute("color"),this.uvAttribute=this.geometry.getAttribute("uv"),this.weightAttribute=null,this.distribution=null}setWeightAttribute(e){return this.weightAttribute=e?this.geometry.getAttribute(e):null,this}build(){const e=this.indexAttribute,t=this.positionAttribute,i=this.weightAttribute,s=e?e.count/3:t.count/3,n=new Float32Array(s);for(let o=0;o<s;o++){let s=1,r=3*o,a=3*o+1,l=3*o+2;e&&(r=e.getX(r),a=e.getX(a),l=e.getX(l)),i&&(s=i.getX(r)+i.getX(a)+i.getX(l)),m.a.fromBufferAttribute(t,r),m.b.fromBufferAttribute(t,a),m.c.fromBufferAttribute(t,l),s*=m.getArea(),n[o]=s}const r=new Float32Array(s);let a=0;for(let o=0;o<s;o++)a+=n[o],r[o]=a;return this.distribution=r,this}setRandomGenerator(e){return this.randomFunction=e,this}sample(e,t,i,s){const n=this._sampleFaceIndex();return this._sampleFace(n,e,t,i,s)}_sampleFaceIndex(){const e=this.distribution[this.distribution.length-1];return this._binarySearch(this.randomFunction()*e)}_binarySearch(e){const t=this.distribution;let i=0,s=t.length-1,n=-1;for(;i<=s;){const r=Math.ceil((i+s)/2);if(0===r||t[r-1]<=e&&t[r]>e){n=r;break}e<t[r]?s=r-1:i=r+1}return n}_sampleFace(e,t,i,s,n){let r=this.randomFunction(),a=this.randomFunction();r+a>1&&(r=1-r,a=1-a);const o=this.indexAttribute;let l=3*e,u=3*e+1,c=3*e+2;return o&&(l=o.getX(l),u=o.getX(u),c=o.getX(c)),m.a.fromBufferAttribute(this.positionAttribute,l),m.b.fromBufferAttribute(this.positionAttribute,u),m.c.fromBufferAttribute(this.positionAttribute,c),t.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),void 0!==i&&(void 0!==this.normalAttribute?(m.a.fromBufferAttribute(this.normalAttribute,l),m.b.fromBufferAttribute(this.normalAttribute,u),m.c.fromBufferAttribute(this.normalAttribute,c),i.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)).normalize()):m.getNormal(i)),void 0!==s&&void 0!==this.colorAttribute&&(m.a.fromBufferAttribute(this.colorAttribute,l),m.b.fromBufferAttribute(this.colorAttribute,u),m.c.fromBufferAttribute(this.colorAttribute,c),g.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),s.r=g.x,s.g=g.y,s.b=g.z),void 0!==n&&void 0!==this.uvAttribute&&(p.fromBufferAttribute(this.uvAttribute,l),v.fromBufferAttribute(this.uvAttribute,u),f.fromBufferAttribute(this.uvAttribute,c),n.set(0,0).addScaledVector(p,r).addScaledVector(v,a).addScaledVector(f,1-(r+a))),this}}class y{constructor(e,t){n(this,"textureSize"),n(this,"dataTextures"),n(this,"eventEmitter"),n(this,"currentAtlas",null),this.eventEmitter=e,this.textureSize=t,this.dataTextures=new Map,this.updateServiceState("ready")}setTextureSize(e){this.textureSize!==e&&(this.textureSize=e,this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null))}async getDataTexture(e){const t=this.dataTextures.get(e.uuid);if(t)return t;var i,s;const n=function(e,t){const i=new a.BufferGeometry;i.setAttribute("position",new a.BufferAttribute(new Float32Array(e.position),3)),e.normal&&i.setAttribute("normal",new a.BufferAttribute(new Float32Array(e.normal),3));const s=new a.MeshBasicMaterial,n=new a.Mesh(i,s);n.scale.set(e.scale.x,e.scale.y,e.scale.z);const r=new x(n).build(),o=new Float32Array(t*t*4),l=new a.Vector3;for(let a=0;a<t;a++)for(let i=0;i<t;i++){const s=a*t+i;r.sample(l),o[4*s]=l.x*e.scale.x,o[4*s+1]=l.y*e.scale.y,o[4*s+2]=l.z*e.scale.z,o[4*s+3]=.01*(Math.random()-.5)}return o}({position:(i=e).geometry.attributes.position.array,normal:null==(s=i.geometry.attributes.normal)?void 0:s.array,scale:{x:i.scale.x,y:i.scale.y,z:i.scale.z}},this.textureSize),r=u(n,this.textureSize);return r.name=e.name,this.dataTextures.set(e.uuid,r),r}async dispose(){this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null),this.updateServiceState("disposed")}updateServiceState(e){this.eventEmitter.emit("serviceStateUpdated",{type:"data-texture",state:e})}async createSequenceDataTextureAtlas(e,t){this.updateServiceState("loading"),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null);const i=e.length;if(0===i)throw new Error("Mesh array cannot be empty.");const s=t*i,n=t,r=new Float32Array(s*n*4);try{for(let n=0;n<i;n++){const i=e[n],a=(await this.getDataTexture(i)).image.data;for(let e=0;e<t;e++)for(let i=0;i<t;i++){const o=4*(e*t+i),l=4*(e*s+(i+n*t));r[l]=a[o],r[l+1]=a[o+1],r[l+2]=a[o+2],r[l+3]=a[o+3]}}const o=new a.DataTexture(r,s,n,a.RGBAFormat,a.FloatType);return o.needsUpdate=!0,o.name=`atlas-${e.map((e=>e.name)).join("-")}`,this.currentAtlas=o,this.updateServiceState("ready"),o}catch(o){throw this.updateServiceState("error"),o}}}class T{constructor(e){n(this,"size"),n(this,"mesh"),n(this,"matcapMaterial"),n(this,"fallbackGeometry"),n(this,"uniforms"),n(this,"originColor"),n(this,"destinationColor"),n(this,"geometries"),n(this,"uvRefsCache"),n(this,"previousScale"),this.size=e,this.geometries=new Map,this.uvRefsCache=new Map,this.previousScale={x:1,y:1,z:1},this.originColor="grey",this.destinationColor="grey",this.uniforms={uTime:{value:0},uProgress:{value:0},uTexture:{value:null},uVelocity:{value:null},uOriginTexture:{value:null},uDestinationTexture:{value:null}},this.matcapMaterial=new a.ShaderMaterial({uniforms:this.uniforms,vertexShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform sampler2D uVelocity;\nuniform float uTime;\nvarying vec3 vNormal;\nattribute vec2 uvRef;\nvarying vec3 vViewPosition;\n\nvec3 rotate3D(vec3 v, vec3 vel) {\n vec3 pos = v;\n vec3 up = vec3(0, 1, 0);\n vec3 axis = normalize(cross(up, vel));\n float angle = acos(dot(up, normalize(vel)));\n pos = pos * cos(angle) + cross(axis, pos) * sin(angle) + axis * dot(axis, pos) * (1. - cos(angle));\n return pos;\n}\n\nvoid main() {\n vUv = uv;\n vNormal = normal;\n\n vec4 color = texture2D(uTexture, uvRef);\n vec4 velocity = texture2D(uVelocity, uvRef);\n vec3 pos = color.xyz;// apply the texture to the vertex distribution.\n\n vec3 localPosition = position.xyz;\n if (length (velocity.xyz) < 0.0001) {\n velocity.xyz = vec3(0.0, 0.0001, 0.0001);\n }\n localPosition.y *= max(1.0, length(velocity.xyz) * 1000.0);\n localPosition = rotate3D(localPosition, velocity.xyz);\n vNormal = rotate3D(normal, velocity.xyz);\n\n mat4 instanceMat = instanceMatrix;\n instanceMat[3].xyz = pos.xyz;\n\n // unlike the traditional mvMatrix * position, we need to additional multiplication with the instance matrix.\n vec4 modelViewPosition = modelViewMatrix * instanceMat * vec4(localPosition, 1.0);\n\n vViewPosition = - modelViewPosition.xyz;\n\n gl_Position = projectionMatrix * modelViewPosition;\n}\n",fragmentShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\n\nuniform sampler2D uOriginTexture;\nuniform sampler2D uDestinationTexture;\n\nuniform float uProgress;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvoid main() {\n vec3 viewDir = normalize( vViewPosition );\n vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n vec3 y = cross( viewDir, x );\n vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks\n\n vec4 sourceMatcap = texture2D( uOriginTexture, uv );\n vec4 targetMatcap = texture2D( uDestinationTexture, uv );\n\n vec4 matcap = mix(sourceMatcap, targetMatcap, uProgress);\n gl_FragColor = matcap;\n}\n"}),this.setOriginColor(this.originColor),this.setDestinationColor(this.destinationColor),this.fallbackGeometry=new a.BoxGeometry(.001,.001,.001),this.mesh=this.createInstancedMesh(e,this.fallbackGeometry,this.matcapMaterial)}getMesh(){return this.mesh}update(e){const t=this.mesh.material;(t instanceof a.ShaderMaterial||t instanceof a.RawShaderMaterial)&&(t.uniforms.uTime.value=e)}setOriginMatcap(e){this.disposeSolidColorOriginTexture(),this.matcapMaterial.uniforms.uOriginTexture.value=e}setDestinationMatcap(e){this.disposeSolidColorDestinationTexture(),this.matcapMaterial.uniforms.uDestinationTexture.value=e}setProgress(e){e=Math.max(0,e),e=Math.min(1,e),this.matcapMaterial.uniforms.uProgress.value=e}setGeometrySize(e){this.mesh.geometry.scale(1/this.previousScale.x,1/this.previousScale.y,1/this.previousScale.z),this.mesh.geometry.scale(e.x,e.y,e.z),this.previousScale=e}useMatcapMaterial(){this.mesh.material=this.matcapMaterial}useGeometry(e){const t=this.geometries.get(e);t&&(this.mesh.geometry=t)}updateVelocityTexture(e){this.matcapMaterial.uniforms.uVelocity.value=e}updatePositionTexture(e){this.matcapMaterial.uniforms.uTexture.value=e}resize(e){if(this.size===e)return{current:this.mesh,previous:this.mesh};this.size=e;const t=this.mesh;return this.mesh=this.createInstancedMesh(e,t.geometry,t.material),{current:this.mesh,previous:t}}dispose(){this.mesh.dispose(),this.geometries.forEach((e=>e.dispose())),this.disposeSolidColorOriginTexture(),this.disposeSolidColorDestinationTexture(),this.matcapMaterial.dispose(),this.uvRefsCache.clear(),this.geometries.clear()}registerGeometry(e,t){const i=this.geometries.get(e);if(i&&i===t)return;const s=this.createUVRefs(this.size);t.setAttribute("uvRef",s),this.geometries.set(e,t),this.mesh.geometry===i&&(this.mesh.geometry=t),null==i||i.dispose()}setOriginColor(e){this.disposeSolidColorOriginTexture(),this.originColor=e,this.uniforms.uOriginTexture.value=this.createSolidColorDataTexture(e)}setDestinationColor(e){this.disposeSolidColorDestinationTexture(),this.destinationColor=e,this.uniforms.uDestinationTexture.value=this.createSolidColorDataTexture(e)}createUVRefs(e){const t=this.uvRefsCache.get(e);if(t)return t;const i=new Float32Array(e*e*2);for(let n=0;n<e;n++)for(let t=0;t<e;t++){const s=n*e+t;i[2*s]=t/(e-1),i[2*s+1]=n/(e-1)}const s=new a.InstancedBufferAttribute(i,2);return this.uvRefsCache.set(e,s),s}createInstancedMesh(e,t,i){(t=t||this.fallbackGeometry).setAttribute("uvRef",this.createUVRefs(e));const s=e*e;return new a.InstancedMesh(t,i,s)}createSolidColorDataTexture(e,t=16){const i=new a.Color(e),s=t,n=t,r=new Uint8Array(s*n*4),o=Math.floor(255*i.r),l=Math.floor(255*i.g),u=Math.floor(255*i.b);for(let a=0;a<s*n;a++){const e=4*a;r[e]=o,r[e+1]=l,r[e+2]=u,r[e+3]=255}const c=new a.DataTexture(r,s,n,a.RGBAFormat);return c.type=a.UnsignedByteType,c.wrapS=a.RepeatWrapping,c.wrapT=a.RepeatWrapping,c.minFilter=a.NearestFilter,c.magFilter=a.NearestFilter,c.needsUpdate=!0,c}disposeSolidColorOriginTexture(){this.originColor&&(this.originColor=null,this.uniforms.uOriginTexture.value&&this.uniforms.uOriginTexture.value.dispose())}disposeSolidColorDestinationTexture(){this.destinationColor&&(this.destinationColor=null,this.uniforms.uDestinationTexture.value&&this.uniforms.uDestinationTexture.value.dispose())}}class S{constructor(e,t){n(this,"active",!0),n(this,"raycaster",new a.Raycaster),n(this,"mousePosition",new a.Vector2),n(this,"camera"),n(this,"meshSequenceGeometries",[]),n(this,"meshSequenceUUIDs",[]),n(this,"overallProgress",0),n(this,"intersectionMesh",new a.Mesh),n(this,"geometryNeedsUpdate"),n(this,"eventEmitter"),n(this,"blendedGeometry"),n(this,"intersection"),this.camera=t,this.eventEmitter=e,this.geometryNeedsUpdate=!0}setActive(e){this.active=e,e||(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}}))}getIntersectionMesh(){return this.intersectionMesh}setCamera(e){this.camera=e}setMeshSequence(e){this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],e&&0!==e.length?(e.forEach((e=>{if(e&&e.geometry){const t=e.geometry.clone();t.applyMatrix4(e.matrixWorld),this.meshSequenceGeometries.push(t),this.meshSequenceUUIDs.push(e.uuid)}else console.warn("Invalid mesh provided to IntersectionService sequence.")})),this.geometryNeedsUpdate=!0):this.geometryNeedsUpdate=!0}setOverallProgress(e){const t=a.MathUtils.clamp(e,0,1);this.overallProgress!==t&&(this.overallProgress=t,this.geometryNeedsUpdate=!0)}setPointerPosition(e){e&&this.mousePosition.copy(e)}calculate(e){var t,i,s;if(!this.active||!this.camera||0===this.meshSequenceGeometries.length)return void(this.intersection&&(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}})));let n;this.geometryNeedsUpdate&&(this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),this.blendedGeometry=this.getBlendedGeometry(),this.geometryNeedsUpdate=!1,this.blendedGeometry?this.intersectionMesh.geometry!==this.blendedGeometry&&(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry):(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=new a.BufferGeometry)),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.blendedGeometry&&this.blendedGeometry.attributes.position&&(n=this.getFirstIntersection(this.camera,this.intersectionMesh));if((null==(t=this.intersection)?void 0:t.x)!==(null==n?void 0:n.x)||(null==(i=this.intersection)?void 0:i.y)!==(null==n?void 0:n.y)||(null==(s=this.intersection)?void 0:s.z)!==(null==n?void 0:n.z)||this.intersection&&!n||!this.intersection&&n)if(this.intersection=n,this.intersection){const t=new a.Vector3(this.intersection.x,this.intersection.y,this.intersection.z),i=e.worldToLocal(t.clone());this.intersection.set(i.x,i.y,i.z,1),this.eventEmitter.emit("interactionPositionUpdated",{position:this.intersection})}else this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}});return this.intersection}dispose(){var e;this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),null==(e=this.intersectionMesh.geometry)||e.dispose()}updateIntersectionMesh(e){this.blendedGeometry&&this.blendedGeometry.uuid!==this.intersectionMesh.geometry.uuid&&(this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry),this.intersectionMesh.matrix.copy(e.matrixWorld),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.intersectionMesh.matrixAutoUpdate=!1,this.intersectionMesh.updateMatrixWorld(!0)}getFirstIntersection(e,t){this.raycaster.setFromCamera(this.mousePosition,e);const i=this.raycaster.intersectObject(t,!1);if(i.length>0&&i[0].point){const e=i[0].point;return new a.Vector4(e.x,e.y,e.z,1)}}getBlendedGeometry(){const e=this.meshSequenceGeometries.length;if(0===e)return;if(1===e)return this.meshSequenceGeometries[0];const t=e-1,i=1/t,s=this.overallProgress*t;let n=Math.floor(s),r=n+1;n=a.MathUtils.clamp(n,0,t),r=a.MathUtils.clamp(r,0,t);let o=0;i>0&&(o=s-n),this.overallProgress>=1&&(n=t,r=t,o=1),o=a.MathUtils.clamp(o,0,1);const l=this.meshSequenceGeometries[n],u=this.meshSequenceGeometries[r];return l&&u?n===r?l:this.blendGeometry(l,u,o):(console.error("IntersectionService: Invalid geometries found for blending at indices",n,r),this.meshSequenceGeometries[0])}blendGeometry(e,t,i){const s=new a.BufferGeometry,n=e.attributes.position.array,r=t.attributes.position.array,o=new Float32Array(n.length);for(let l=0;l<n.length;l+=3){const e=new a.Vector3(n[l],n[l+1],n[l+2]),t=new a.Vector3(r[l],r[l+1],r[l+2]),s=(new a.Vector3).lerpVectors(e,t,i);o[l]=s.x,o[l+1]=s.y,o[l+2]=s.z}return s.setAttribute("position",new a.BufferAttribute(o,3)),e.attributes.normal&&s.setAttribute("normal",e.attributes.normal.clone()),e.attributes.uv&&s.setAttribute("uv",e.attributes.uv.clone()),e.index&&s.setIndex(e.index.clone()),s}}const M=new t.OrthographicCamera(-1,1,1,-1,0,1);class P extends t.BufferGeometry{constructor(){super(),this.setAttribute("position",new t.Float32BufferAttribute([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new t.Float32BufferAttribute([0,2,0,0,2,0],2))}}const w=new P;class A{constructor(e){this._mesh=new t.Mesh(w,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,M)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class b{constructor(e,i,s){this.variables=[],this.currentTextureIndex=0;let n=t.FloatType;const r={passThruTexture:{value:null}},a=u("uniform sampler2D passThruTexture;\n\nvoid main() {\n\n\tvec2 uv = gl_FragCoord.xy / resolution.xy;\n\n\tgl_FragColor = texture2D( passThruTexture, uv );\n\n}\n",r),o=new A(a);function l(t){t.defines.resolution="vec2( "+e.toFixed(1)+", "+i.toFixed(1)+" )"}function u(e,i){i=i||{};const s=new t.ShaderMaterial({name:"GPUComputationShader",uniforms:i,vertexShader:"void main()\t{\n\n\tgl_Position = vec4( position, 1.0 );\n\n}\n",fragmentShader:e});return l(s),s}this.setDataType=function(e){return n=e,this},this.addVariable=function(e,i,s){const n={name:e,initialValueTexture:s,material:this.createShaderMaterial(i),dependencies:null,renderTargets:[],wrapS:null,wrapT:null,minFilter:t.NearestFilter,magFilter:t.NearestFilter};return this.variables.push(n),n},this.setVariableDependencies=function(e,t){e.dependencies=t},this.init=function(){if(0===s.capabilities.maxVertexTextures)return"No support for vertex shader textures.";for(let t=0;t<this.variables.length;t++){const s=this.variables[t];s.renderTargets[0]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),s.renderTargets[1]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),this.renderTexture(s.initialValueTexture,s.renderTargets[0]),this.renderTexture(s.initialValueTexture,s.renderTargets[1]);const n=s.material,r=n.uniforms;if(null!==s.dependencies)for(let e=0;e<s.dependencies.length;e++){const t=s.dependencies[e];if(t.name!==s.name){let e=!1;for(let i=0;i<this.variables.length;i++)if(t.name===this.variables[i].name){e=!0;break}if(!e)return"Variable dependency not found. Variable="+s.name+", dependency="+t.name}r[t.name]={value:null},n.fragmentShader="\nuniform sampler2D "+t.name+";\n"+n.fragmentShader}}return this.currentTextureIndex=0,null},this.compute=function(){const e=this.currentTextureIndex,t=0===this.currentTextureIndex?1:0;for(let i=0,s=this.variables.length;i<s;i++){const s=this.variables[i];if(null!==s.dependencies){const t=s.material.uniforms;for(let i=0,n=s.dependencies.length;i<n;i++){const n=s.dependencies[i];t[n.name].value=n.renderTargets[e].texture}}this.doRenderTarget(s.material,s.renderTargets[t])}this.currentTextureIndex=t},this.getCurrentRenderTarget=function(e){return e.renderTargets[this.currentTextureIndex]},this.getAlternateRenderTarget=function(e){return e.renderTargets[0===this.currentTextureIndex?1:0]},this.dispose=function(){o.dispose();const e=this.variables;for(let t=0;t<e.length;t++){const i=e[t];i.initialValueTexture&&i.initialValueTexture.dispose();const s=i.renderTargets;for(let e=0;e<s.length;e++){s[e].dispose()}}},this.addResolutionDefine=l,this.createShaderMaterial=u,this.createRenderTarget=function(s,r,a,o,l,u){s=s||e,r=r||i,a=a||t.ClampToEdgeWrapping,o=o||t.ClampToEdgeWrapping,l=l||t.NearestFilter,u=u||t.NearestFilter;return new t.WebGLRenderTarget(s,r,{wrapS:a,wrapT:o,minFilter:l,magFilter:u,format:t.RGBAFormat,type:n,depthBuffer:!1})},this.createTexture=function(){const s=new Float32Array(e*i*4),n=new t.DataTexture(s,e,i,t.RGBAFormat,t.FloatType);return n.needsUpdate=!0,n},this.renderTexture=function(e,t){r.passThruTexture.value=e,this.doRenderTarget(a,t),r.passThruTexture.value=null},this.doRenderTarget=function(e,t){const i=s.getRenderTarget(),n=s.xr.enabled,r=s.shadowMap.autoUpdate;s.xr.enabled=!1,s.shadowMap.autoUpdate=!1,o.material=e,s.setRenderTarget(t),o.render(s),o.material=a,s.xr.enabled=n,s.shadowMap.autoUpdate=r,s.setRenderTarget(i)}}}class V{constructor(e,t,i){n(this,"gpuComputationRenderer"),n(this,"webGLRenderer"),n(this,"velocityVar"),n(this,"positionVar"),n(this,"initialPositionDataTexture"),n(this,"initialVelocityDataTexture"),n(this,"positionAtlasTexture",null),n(this,"interactionPosition"),n(this,"lastKnownPositionDataTexture"),n(this,"lastKnownVelocityDataTexture"),this.webGLRenderer=t,this.gpuComputationRenderer=new b(e,e,this.webGLRenderer),!t.capabilities.isWebGL2&&t.extensions.get("OES_texture_float")?this.gpuComputationRenderer.setDataType(a.FloatType):t.capabilities.isWebGL2||this.gpuComputationRenderer.setDataType(a.HalfFloatType),this.initialPositionDataTexture=i??function(e){const t=new Float32Array(e*e*4);for(let i=0;i<e;i++)for(let s=0;s<e;s++){const n=i*e+s;let r=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1),o=Math.sin(a)*Math.cos(r),l=Math.sin(a)*Math.sin(r),u=Math.cos(a);t[4*n]=o,t[4*n+1]=l,t[4*n+2]=u,t[4*n+3]=.01*(Math.random()-.5)}return u(t,e)}(e),this.initialVelocityDataTexture=function(e){return u(new Float32Array(4*e*e),e)}(e),this.interactionPosition=new a.Vector4(0,0,0,0),this.velocityVar=this.gpuComputationRenderer.addVariable("uCurrentVelocity",'\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform float uMaxRepelDistance;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress;\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function (same as in position shader)\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize;\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex), uv.y);\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n float offset = rand(uv);\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas (same logic as position shader) ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n int indexA = int(floor(scaledProgress));\n int indexB = min(indexA + 1, uNumMeshes - 1);\n indexA = min(indexA, uNumMeshes - 1);\n float localProgress = fract(scaledProgress);\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0;\n }\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n vec3 finalVelocity = currentVelocity * 0.9; // Dampening\n\n // Particle traction force towards target (influences velocity)\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n if (dist > 0.01) {\n // Add force proportional to distance and traction setting\n finalVelocity += direction * dist * 0.01 * uTractionForce; // Adjust multiplier as needed\n }\n\n // Mouse repel force\n if (uInteractionPosition.w > 0.0) { // Check if interaction is active (w component)\n float pointerDistance = distance(currentPosition, uInteractionPosition.xyz);\n if (pointerDistance < uMaxRepelDistance) {\n float mouseRepelModifier = smoothstep(uMaxRepelDistance, 0.0, pointerDistance); // Smoother falloff\n vec3 repelDirection = normalize(currentPosition - uInteractionPosition.xyz);\n // Apply force based on proximity and interaction strength (w)\n finalVelocity += repelDirection * mouseRepelModifier * uInteractionPosition.w * 0.01; // Adjust multiplier\n }\n }\n\n // Optional: Reset position if particle "dies" and respawns (lifespan logic)\n float lifespan = 20.0;\n float age = mod(uTime * 0.1 + lifespan * offset, lifespan); // Adjust time scale\n if (age < 0.05) { // Small window for reset\n finalVelocity = vec3(0.0); // Reset velocity on respawn\n // Note: Resetting position directly here might cause jumps.\n // It\'s often better handled in the position shader or by ensuring\n // strong attraction force when dist is large.\n }\n\n\n gl_FragColor = vec4(finalVelocity, 1.0);\n}\n',this.initialVelocityDataTexture),this.positionVar=this.gpuComputationRenderer.addVariable("uCurrentPosition","\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress; // (0.0 to 1.0)\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function to get position from atlas\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize; // Assuming height is single texture size\n\n // Calculate UV within the specific mesh's section of the atlas\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(\n uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex),\n uv.y // Assuming vertical layout doesn't change y\n );\n\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n // GPGPU UV calculation\n vec2 uv = gl_FragCoord.xy / resolution.xy; // resolution is the size of the *output* texture (e.g., 256x256)\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n\n int indexA = int(floor(scaledProgress));\n // Clamp indexB to avoid going out of bounds\n int indexB = min(indexA + 1, uNumMeshes - 1);\n\n // Ensure indexA is also within bounds (important if uOverallProgress is exactly 1.0)\n indexA = min(indexA, uNumMeshes - 1);\n\n\n float localProgress = fract(scaledProgress);\n\n // Handle edge case where progress is exactly 1.0\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0; // or 0.0 depending on how you want to handle it\n }\n\n\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n // Particle attraction to target position\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n\n vec3 finalPosition = currentPosition;\n\n // Apply attraction force (simplified mix)\n if (dist > 0.01) { // Only apply if significantly far\n finalPosition = mix(currentPosition, targetPosition, 0.1 * uTractionForce);\n }\n\n finalPosition += currentVelocity;\n gl_FragColor = vec4(finalPosition, 1.0);\n}\n",this.initialPositionDataTexture),this.velocityVar.material.uniforms.uTime={value:0},this.velocityVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.velocityVar.material.uniforms.uCurrentPosition={value:null},this.velocityVar.material.uniforms.uTractionForce={value:.1},this.velocityVar.material.uniforms.uMaxRepelDistance={value:.3},this.velocityVar.material.uniforms.uPositionAtlas={value:null},this.velocityVar.material.uniforms.uOverallProgress={value:0},this.velocityVar.material.uniforms.uNumMeshes={value:1},this.velocityVar.material.uniforms.uSingleTextureSize={value:e},this.positionVar.material.uniforms.uTime={value:0},this.positionVar.material.uniforms.uTractionForce={value:.1},this.positionVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.positionVar.material.uniforms.uCurrentPosition={value:null},this.positionVar.material.uniforms.uCurrentVelocity={value:null},this.positionVar.material.uniforms.uPositionAtlas={value:null},this.positionVar.material.uniforms.uOverallProgress={value:0},this.positionVar.material.uniforms.uNumMeshes={value:1},this.positionVar.material.uniforms.uSingleTextureSize={value:e},this.gpuComputationRenderer.setVariableDependencies(this.positionVar,[this.positionVar,this.velocityVar]),this.gpuComputationRenderer.setVariableDependencies(this.velocityVar,[this.velocityVar,this.positionVar]);const s=this.gpuComputationRenderer.init();if(null!==s)throw new Error("Failed to initialize SimulationRenderer: "+s);this.positionVar.material.uniforms.uPositionAtlas.value=this.initialPositionDataTexture,this.positionVar.material.uniforms.uNumMeshes.value=1,this.velocityVar.material.uniforms.uNumMeshes.value=1,this.positionVar.material.uniforms.uSingleTextureSize.value=e,this.velocityVar.material.uniforms.uSingleTextureSize.value=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t&&e.dataTexture.image.height===e.singleTextureSize||console.error(`SimulationRenderer: Atlas texture dimension mismatch! Expected ${t}x${e.singleTextureSize}, Got ${e.dataTexture.image.width}x${e.dataTexture.image.height}`),this.positionAtlasTexture=e.dataTexture;const i=e.numMeshes>0?e.numMeshes:1;this.positionVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.positionVar.material.uniforms.uNumMeshes.value=i,this.positionVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.velocityVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.velocityVar.material.uniforms.uNumMeshes.value=i,this.velocityVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setOverallProgress(e){const t=h(e,0,1);this.positionVar.material.uniforms.uOverallProgress.value=t,this.velocityVar.material.uniforms.uOverallProgress.value=t}setMaxRepelDistance(e){this.velocityVar.material.uniforms.uMaxRepelDistance.value=e}setVelocityTractionForce(e){this.velocityVar.material.uniforms.uTractionForce.value=e}setPositionalTractionForce(e){this.positionVar.material.uniforms.uTractionForce.value=e}setInteractionPosition(e){this.interactionPosition.copy(e)}dispose(){var e,t;this.gpuComputationRenderer.dispose(),null==(e=this.initialPositionDataTexture)||e.dispose(),null==(t=this.initialVelocityDataTexture)||t.dispose(),this.positionAtlasTexture=null}compute(e){this.velocityVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.gpuComputationRenderer.compute(),this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}}class R{constructor(e,t,i){n(this,"state"),n(this,"textureSize"),n(this,"overallProgress"),n(this,"velocityTractionForce"),n(this,"positionalTractionForce"),n(this,"simulationRenderer"),n(this,"webGLRenderer"),n(this,"eventEmitter"),n(this,"currentAtlasEntry",null),n(this,"lastKnownVelocityDataTexture"),n(this,"lastKnownPositionDataTexture"),this.eventEmitter=e,this.webGLRenderer=i,this.textureSize=t,this.overallProgress=0,this.velocityTractionForce=.1,this.positionalTractionForce=.1,this.updateServiceState("initializing"),this.simulationRenderer=new V(this.textureSize,this.webGLRenderer),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture(),this.updateServiceState("ready")}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t?(this.currentAtlasEntry=e,this.simulationRenderer.setPositionAtlas(e)):this.eventEmitter.emit("invalidRequest",{message:"Atlas texture width mismatch."})}setOverallProgress(e){this.overallProgress=e,this.simulationRenderer.setOverallProgress(this.overallProgress)}setTextureSize(e){this.updateServiceState("initializing"),this.simulationRenderer.dispose(),this.textureSize=e,this.simulationRenderer=new V(e,this.webGLRenderer),this.updateServiceState("ready")}setVelocityTractionForce(e){this.velocityTractionForce=e,this.simulationRenderer.setVelocityTractionForce(this.velocityTractionForce)}setPositionalTractionForce(e){this.positionalTractionForce=e,this.simulationRenderer.setPositionalTractionForce(this.positionalTractionForce)}compute(e){"ready"===this.state&&(this.simulationRenderer.compute(e),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture())}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}dispose(){this.updateServiceState("disposed"),this.simulationRenderer.dispose(),this.currentAtlasEntry=null}updateServiceState(e){this.state=e,this.eventEmitter.emit("serviceStateUpdated",{type:"simulation",state:e})}setInteractionPosition(e){this.simulationRenderer.setInteractionPosition(e)}setMaxRepelDistance(e){this.simulationRenderer.setMaxRepelDistance(e)}}class C{constructor(){n(this,"execStatus",new Map)}get(e){const t=this.execStatus.get(e);return t||(this.execStatus.set(e,"idle"),"idle")}set(e,t){this.execStatus.set(e,t)}}class D{constructor(e){n(this,"eventEmitter"),n(this,"transitions",new Map),n(this,"execStatus"),n(this,"ongoingTransitions",new Map),this.eventEmitter=e,this.execStatus=new C,this.eventEmitter.on("transitionCancelled",this.handleTransitionCancelledEvent.bind(this))}enqueue(e,t,i={}){const s={...t,...i,cancelled:!1,duration:.001*t.duration};this.getQueue(e).push(s)}compute(e){this.transitions.forEach(((t,i)=>{var s;if(t.length&&!this.ongoingTransitions.has(i)){const n=t.shift();n&&(this.ongoingTransitions.set(i,{...n,startTime:e}),null==(s=n.onTransitionBegin)||s.call(n))}})),this.ongoingTransitions.forEach(((t,i)=>{var s,n,r;if(t.cancelled)return null==(s=t.onTransitionCancelled)||s.call(t),void this.ongoingTransitions.delete(i);const{startTime:a,duration:o,easing:l}=t,u=e-a,c=h(l(Math.min(1,u/o)),0,1);this.emitTransitionProgress(i,c),null==(n=t.onTransitionProgress)||n.call(t,c),c>=1&&(this.emitTransitionFinished(i),null==(r=t.onTransitionFinished)||r.call(t),this.ongoingTransitions.delete(i))}))}getQueue(e){const t=this.transitions.get(e);return t||(this.transitions.set(e,[]),this.transitions.get(e)??[])}handleTransitionCancelledEvent({type:e}){var t;const i=this.getQueue(e);for(;i.length;)i.pop();const s=this.ongoingTransitions.get(e);s&&(s.cancelled=!0,null==(t=s.onTransitionCancelled)||t.call(s))}emitTransitionProgress(e,t){this.eventEmitter.emit("transitionProgressed",{type:e,progress:t})}emitTransitionFinished(e){this.eventEmitter.emit("transitionFinished",{type:e})}}return e.ParticlesEngine=class{constructor(e){n(this,"simulationRendererService"),n(this,"renderer"),n(this,"scene"),n(this,"serviceStates"),n(this,"assetService"),n(this,"dataTextureManager"),n(this,"instancedMeshManager"),n(this,"transitionService"),n(this,"engineState"),n(this,"intersectionService"),n(this,"meshSequenceAtlasTexture",null),n(this,"eventEmitter");const{scene:t,renderer:i,camera:s,textureSize:r,useIntersection:a=!0}=e;this.eventEmitter=new l,this.serviceStates=this.getInitialServiceStates(),this.eventEmitter.on("serviceStateUpdated",this.handleServiceStateUpdated.bind(this)),this.scene=t,this.renderer=i,this.engineState=this.initialEngineState(e),this.assetService=new d(this.eventEmitter),this.transitionService=new D(this.eventEmitter),this.dataTextureManager=new y(this.eventEmitter,r),this.simulationRendererService=new R(this.eventEmitter,r,this.renderer),this.instancedMeshManager=new T(r),this.instancedMeshManager.useMatcapMaterial(),this.scene.add(this.instancedMeshManager.getMesh()),this.intersectionService=new S(this.eventEmitter,s),a||this.intersectionService.setActive(!1),this.eventEmitter.on("interactionPositionUpdated",this.handleInteractionPositionUpdated.bind(this))}render(e){const t=e/1e3;this.transitionService.compute(t),this.intersectionService.calculate(this.instancedMeshManager.getMesh()),this.simulationRendererService.compute(t),this.instancedMeshManager.update(t),this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture()),this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture())}setOriginMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.originMatcapID=e,this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(e))}setDestinationMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.destinationMatcapID=e,this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(e))}setOriginColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setOriginColor(e)}setDestinationColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setDestinationColor(e)}setOriginTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setOriginMatcap(e):this.setOriginColor(e)}setDestinationTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setDestinationMatcap(e):this.setDestinationColor(e)}setMatcapProgress(e,t=!1){const i=h(e,0,1);t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.matcapTransitionProgress=i,this.instancedMeshManager.setProgress(i)}async setTextureSize(e){this.engineState.textureSize!==e&&(this.engineState.textureSize=e,this.dataTextureManager.setTextureSize(e),this.simulationRendererService.setTextureSize(e),this.instancedMeshManager.resize(e),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce),this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce),this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setOverallProgress(this.engineState.overallProgress),this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID)),this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID)),this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress),this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale))}registerMesh(e,t){this.assetService.register(e,t)}registerMatcap(e,t){this.assetService.register(e,t)}async fetchAndRegisterMesh(e,t){return await this.assetService.loadMeshAsync(e,t)}async fetchAndRegisterMatcap(e,t){return await this.assetService.loadTextureAsync(e,t)}useIntersect(e){this.intersectionService.setActive(e),this.engineState.useIntersect=e,e||(this.engineState.pointerPosition={x:-99999999,y:-99999999},this.simulationRendererService.setInteractionPosition({x:0,y:0,z:0,w:0}))}setPointerPosition(e){this.engineState.useIntersect&&(this.engineState.pointerPosition=e,this.intersectionService.setPointerPosition(e))}setGeometrySize(e){this.engineState.instanceGeometryScale=e,this.instancedMeshManager.setGeometrySize(e)}setVelocityTractionForce(e){this.engineState.velocityTractionForce=e,this.simulationRendererService.setVelocityTractionForce(e)}setPositionalTractionForce(e){this.engineState.positionalTractionForce=e,this.simulationRendererService.setPositionalTractionForce(e)}setMaxRepelDistance(e){this.engineState.maxRepelDistance=e,this.simulationRendererService.setMaxRepelDistance(e)}async setMeshSequence(e){if(!e||e.length<1)return this.eventEmitter.emit("invalidRequest",{message:"Mesh sequence must contain at least one mesh ID."}),this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=e,this.engineState.overallProgress=0;const t=e.map((e=>this.assetService.getMesh(e))).filter((e=>null!==e));if(t.length!==e.length){const i=e.filter((e=>!this.assetService.getMesh(e)));if(console.warn(`Could not find meshes for IDs: ${i.join(", ")}. Proceeding with ${t.length} found meshes.`),this.eventEmitter.emit("invalidRequest",{message:`Could not find meshes for IDs: ${i.join(", ")}`}),t.length<1)return this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=t.map((e=>e.name))}try{this.meshSequenceAtlasTexture=await this.dataTextureManager.createSequenceDataTextureAtlas(t,this.engineState.textureSize),this.simulationRendererService.setPositionAtlas({dataTexture:this.meshSequenceAtlasTexture,textureSize:this.engineState.textureSize,numMeshes:this.engineState.meshSequence.length,singleTextureSize:this.engineState.textureSize}),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setMeshSequence(t),this.intersectionService.setOverallProgress(this.engineState.overallProgress)}catch(i){console.error("Failed during mesh sequence setup:",i),this.meshSequenceAtlasTexture=null}}setOverallProgress(e,t=!0){t&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const i=h(e,0,1);this.engineState.overallProgress=i,this.simulationRendererService.setOverallProgress(i),this.intersectionService.setOverallProgress(i)}scheduleMatcapTransition(e,t,i=o,s=1e3,n=!1,r={}){n&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:i,duration:s},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginMatcap(e,!1),this.setDestinationMatcap(t,!1),this.setMatcapProgress(0,!1),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1,!1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:r.onTransitionCancelled})}scheduleTextureTransition(e,t,i={}){const s=(null==i?void 0:i.easing)??o,n=(null==i?void 0:i.duration)??1e3,r={onTransitionBegin:null==i?void 0:i.onTransitionBegin,onTransitionProgress:null==i?void 0:i.onTransitionProgress,onTransitionFinished:null==i?void 0:i.onTransitionFinished,onTransitionCancelled:null==i?void 0:i.onTransitionCancelled};(null==i?void 0:i.override)&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:s,duration:n},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginTexture(e),this.setDestinationTexture(t),this.setMatcapProgress(0),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:()=>{var e;null==(e=r.onTransitionCancelled)||e.call(r)}})}scheduleMeshSequenceTransition(e,t=1e3,i=o,s={},n=!0){n&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const r=this.engineState.overallProgress,a=e-r,l={duration:t,easing:i},u={...s,onTransitionProgress:e=>{var t;const i=r+a*e;this.setOverallProgress(i,!1),null==(t=s.onTransitionProgress)||t.call(s,i)},onTransitionBegin:s.onTransitionBegin,onTransitionFinished:()=>{var t;this.setOverallProgress(e,!1),null==(t=s.onTransitionFinished)||t.call(s)},onTransitionCancelled:s.onTransitionCancelled};this.transitionService.enqueue("mesh-sequence",l,u)}handleServiceStateUpdated({type:e,state:t}){this.serviceStates[e]=t}getObject(){return this.instancedMeshManager.getMesh()}getMeshIDs(){return this.assetService.getMeshIDs()}getMatcapIDs(){return this.assetService.getTextureIDs()}getMeshes(){return this.assetService.getMeshes()}getTextures(){return this.assetService.getTextures()}getTextureSize(){return this.engineState.textureSize}getUseIntersect(){return this.engineState.useIntersect}getEngineStateSnapshot(){return{...this.engineState}}dispose(){var e,t,i,s,n,r;this.scene&&this.instancedMeshManager&&this.scene.remove(this.instancedMeshManager.getMesh()),null==(e=this.simulationRendererService)||e.dispose(),null==(t=this.instancedMeshManager)||t.dispose(),null==(i=this.intersectionService)||i.dispose(),null==(s=this.assetService)||s.dispose(),null==(n=this.dataTextureManager)||n.dispose(),null==(r=this.eventEmitter)||r.dispose()}initialEngineState(e){return{textureSize:e.textureSize,meshSequence:[],overallProgress:0,originMatcapID:"",destinationMatcapID:"",matcapTransitionProgress:0,velocityTractionForce:.1,positionalTractionForce:.1,maxRepelDistance:.3,pointerPosition:{x:0,y:0},instanceGeometryScale:{x:1,y:1,z:1},useIntersect:e.useIntersection??!0}}getInitialServiceStates(){return{"data-texture":"created","instanced-mesh":"created",matcap:"created",simulation:"created",asset:"created"}}handleInteractionPositionUpdated({position:e}){this.simulationRendererService.setInteractionPosition(e)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({},THREE,three-stdlib);
|
|
2
2
|
//# sourceMappingURL=ionian.iife.js.map
|