@hology/core 0.0.196 → 0.0.197
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/effects/sequence/sequence-action.d.ts +8 -1
- package/dist/effects/sequence/sequence-actor.d.ts +14 -2
- package/dist/effects/sequence/sequence-actor.js +1 -1
- package/dist/effects/sequence/sequence-data.d.ts +67 -2
- package/dist/effects/sequence/sequence-data.js +1 -1
- package/dist/effects/sequence/sequence-definitions.d.ts +11 -7
- package/dist/effects/sequence/sequence-definitions.js +1 -1
- package/dist/effects/sequence/sequence-ops.js +1 -1
- package/dist/effects/sequence/sequence-player.d.ts +59 -2
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/sequence/sequence-value-lane.d.ts +1 -0
- package/dist/effects/sequence/sequence-value-lane.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/builtin/post-process-volume-actor.js +1 -1
- package/dist/gameplay/initiate.d.ts +1 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/render.d.ts +15 -2
- package/dist/gameplay/services/render.js +1 -1
- package/dist/rendering.d.ts +5 -1
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/collision/collision-shape-import.js +1 -1
- package/dist/scene/collision/collision-shape.js +1 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/storage/storage.d.ts +2 -0
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/test/collision-shape-import.test.js +1 -1
- package/dist/test/sequence-camera-control.test.d.ts +2 -0
- package/dist/test/sequence-camera-control.test.js +4 -0
- package/dist/test/sequence-property-parameters.test.d.ts +2 -0
- package/dist/test/sequence-property-parameters.test.js +4 -0
- package/dist/test/storage-case-collision.test.d.ts +2 -0
- package/dist/test/storage-case-collision.test.js +4 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{ConvexPolyhedronCollisionShape as a,SpriteShader as s}from"@hology/core";import{Subject as r}from"rxjs";import*as i from"three";import{BoxGeometry as n,Color as o,Euler as l,Fog as c,FogExp2 as h,Group as p,Material as u,Matrix4 as d,Mesh as m,MeshLambertMaterial as f,MeshPhongMaterial as g,MeshStandardMaterial as y,Object3D as w,PointLight as M,Quaternion as v,Scene as b,Texture as A,Vector2 as S,Vector3 as x,Vector4 as I}from"three";import{attributes as j,batchingUniformFloat as D,batchingUniformVec2 as P,batchingUniformVec3 as C,batchingUniformVec4 as T,bool as E,BooleanExpression as V,BooleanNode as k,colorToNormal as O,float as z,FloatNode as F,ifDefApply as N,mix as B,NodeShaderMaterial as _,rgb as U,rgba as $,RgbNode as W,select as L,standardMaterial as R,Texture2dLookupNode as q,textureSampler2d as G,textureSampler2dArray as J,UniformSampler2dArraySlice as H,varying as X,varyingAttributes as Y,varyingTransformed as Z,vec2 as K,Vec2Node as Q,vec3 as ee,Vec3Node as te,vec4 as ae,Vec4Node as se}from"three-shader-graph";import{Service as re}from"typedi";import{VfxActor as ie}from"../effects/vfx/vfx-actor.js";import{VisualEffect as ne}from"../effects/vfx/vfx-param.js";import{Prefab as oe,PrefabOf as le}from"./objects/prefab.js";import{BaseActor as ce}from"../gameplay/actors/actor.js";import he from"../gameplay/actors/builtin/index.js";import{ActorComponent as pe}from"../gameplay/actors/component.js";import{PhysicsBodyType as ue}from"../gameplay/services/physics/physics-system.js";import{ThreeBlendingMode as de}from"../effects/vfx/vfx-asset.js";import{withInjectionContext as me}from"../gameplay/inject.js";import{RenderingView as fe}from"../rendering.js";import{curveSampler as ge,oneMinus as ye,particleUniforms as we,Sampler2DNode as Me}from"../shader-nodes/index.js";import{LambertShader as ve}from"../shader/builtin/lambert-shader.js";import{LandscapeCompositeShader as be}from"../shader/builtin/landscape-composite-shader";import{LandscapeShader as Ae}from"../shader/builtin/landscape-shader.js";import{StandardShader as Se}from"../shader/builtin/standard-shader.js";import{UnlitShader as xe}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as Ie}from"../shader/parameter.js";import{ArrayMap as je,DefaultMap as De,groupBy as Pe}from"../utils/collections.js";import{iterateMaterials as Ce}from"../utils/materials.js";import{filterChildrenShallow as Te,filterSceneShallow as Ee,findFirstVisibleMesh as Ve,findFirstVisibleObject as ke,traverseAsync as Oe}from"../utils/three/traverse.js";import{AssetMeshInstance as ze,AssetResourceLoader as Fe}from"./asset-resource-loader.js";import{AssetsProvider as Ne}from"./assets-provider.js";import{isCollisionMesh as Be}from"./collision/collision-shape-import.js";import{BoxCollisionShape as _e,PhysicalShapeMesh as Ue}from"./collision/collision-shape.js";import{LandscapeManager as $e}from"./landscape/landscape-manager.js";import{initLandscape as We}from"./landscape/landscape.js";import{SectionGrid as Le,smoothNormalsCrossMeshes as Re}from"./landscape/utils.js";import{createGrassFoliageMaterial as qe}from"./materials/grass-foliage.js";import{createGrassMaterial as Ge}from"./materials/grass.js";import{getMaterialAttribute as Je}from"./materials/utils/material-painting.js";import{createWaterMaterial as He}from"./materials/water.js";import{SerializedParamType as Xe}from"./model.js";import{ShapeLibrary as Ye,ShapeLibraryKeys as Ze}from"./objects/shapes.js";import{ambientLightName as Ke,createSky as Qe,defaultSkyMaterial as et}from"./sky.js";import{Curve2 as tt}from"../utils/curve.js";import{DecalUnlitShader as at}from"../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as st}from"../shader/builtin/decal-standard-shader.js";import{ColorLayer as rt,defaultValueColorLayer as it,defaultValueMaskLayer as nt,MaskLayer as ot}from"../shader/color-layer.js";import{LayeredShader as lt}from"../shader/builtin/layered-shader";import{isColorLayerSerialized as ct}from"../shader/color-layer";import{FogVolume as ht}from"../rendering/fog/fog-volume-actor.js";import{UnscaledSprite as pt}from"../utils/three/unscaled-sprite.js";import{ToonShader as ut}from"../shader/builtin/toon-shader.js";import{BatchedMesh2 as dt}from"./batched-mesh-2.js";import{ParallaxStandardMaterial as mt}from"../shader/builtin/standard-shader";import{parallaxOcclusionMapping as ft}from"../shader-nodes/pom.js";import{traverseVisibleEvery as gt}from"../utils/three/traverse";import{RectAreaLightHelper as yt}from"three/examples/jsm/Addons.js";import{Sequence as wt}from"../effects/sequence/sequence-data.js";const Mt={},vt=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),bt=/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(navigator.userAgent.includes("iPhone")||navigator.userAgent.includes("iPad"))&&!!navigator.userAgent.match(/AppleWebKit/)&&!navigator.userAgent.match(/CriOS/);export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new At(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}let At=class{constructor(e,t,a,s,n,o,l,c,h=[]){this.scene=e,this.dataProvider=t,this.assetsService=a,this.assetManagerService=s,this.renderingView=n,this.shaders=o,this.actorTypes=l,this.actorProvider=c,this.componentTypes=h,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.idToSceneObject=new Map,this.inEditor=!0,this.updated$=new r,this.removed$=new r,this.error$=new r,this.editorActorParamSnapshot=new Map,this.assets=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.pmremGeneratorResults=new WeakMap,this.prefabInstanceChain=[],this.prefabInstanceExposedActorMap=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.assetManagerService.materialProvider=async e=>materialFromAsset(this.assets.get(e)??await this.assetsService.getAsset(e),this.renderingView,this.assetsService,this.assetManagerService,this.shaders),this.originalFog=null,t.onCreate(e=>this.update(e)),t.onUpdate(e=>this.update(e)),t.onRemove(e=>this.remove(e)),this.createAssetSubscription=a.onCreate.subscribe(e=>{this.assets.set(e.id,e)}),this.updateSubscription=a.onUpdate.subscribe(async t=>{if(this.assets.set(t.id,t),"material"==t.type)e.traverse(e=>{if(e instanceof i.Mesh)if(Array.isArray(e.material))for(let a=0;a<e.material.length;a++)this.refreshMaterial(e,e.material[a],t,a);else this.refreshMaterial(e,e.material,t)});else if("mesh"==t.type){this.findByAssetId(t.id).forEach(async e=>{this.remove(e.userData.src);const t=await this.materializeAndInitActor(e.userData.src);this.updated$.next({object:t,source:e.userData.src})});for(const e of this.assets.values())if("prefab"==e.type){if(!e.prefab.objects.some(e=>sa(e,e=>e.assetId==t.id,this.assets)))continue;this.findByAssetId(e.id).forEach(e=>{this.remove(e.userData.src),this.materializeAndInitActor(e.userData.src)})}this.landscapeManagers.forEach(e=>{const a=e.source?.grass?.layers?.some(e=>e.meshes.some(e=>e.assetId===t.id));a&&e.queueRefreshScatter(this.renderingView?.camera.position??new x,!0)})}else"prefab"===t.type?this.findByAssetId(t.id).forEach(e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}):"vfx"===t.type?this.dataProvider.getObjects().forEach(e=>{Vt(e,(e,a)=>{"vfx"===e.type&&e.assetId===t.id&&(this.remove(e),this.materializeAndInitActor(e))})}):"texture"===t.type&&this.scene.traverse(e=>{if(e instanceof m)if(Array.isArray(e.material))for(let a=0;a<e.material.length;a++)this.refreshMaterialTextures(e,e.material[a],t,a);else this.refreshMaterialTextures(e,e.material,t)})})}async refreshMaterialTextures(e,t,a,s){if("texture"!==a.type)return void console.error("Can not refresh material textures. Asset is not a texture",a);const r=await this.assetManagerService.getTexture(a);if(null!=r)if(t instanceof i.ShaderMaterial)for(const[e,s]of Object.entries(t.uniforms))s.value instanceof i.Texture&&s.value.userData.assetId===a.id&&(t.uniforms[e].value=r);else for(const[e,s]of Object.entries(t))s instanceof i.Texture&&s.userData.assetId===a.id&&(t[e]=r);else console.error("Can not refresh material textures. Texture not found",a)}async refreshMaterial(e,t,a,s){const r=t?.userData?.assetId;if(r!==a.id){const e=this.assets.get(r);let t=!1;if(null!=e)for(const s of Object.values(e.material.shaderParams)){if(s.type===Xe.Material&&s.value===a.id){t=!0;break}if(s.type===Xe.Array&&"element"in s&&s.element===Xe.Material&&s.value.includes(a.id)){t=!0;break}}if(!t)return}const i=await materialFromAsset(this.assets.get(r),this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1),n=i.userData;i.userData=t.userData,i.userData.hasBloom=n.hasBloom,i.userData.reflective=n.reflective,i.userData.outlineParameters=n.outlineParameters,null!=s?Wt(e.material[s],i)||(e.material[s]=i):Wt(e.material,i)||(e.material=i,e===this.sky&&this.applySkySettings(e.material))}getTopLevelActors(){return Array.from(this.materializedActors.entries()).filter(([e,t])=>!e.includes("/")).map(([,e])=>e)}get actorInstances(){return Array.from(this.materializedActors.values())}async initTextures(){const e=[];if(await Promise.all(this.dataProvider.getObjects().filter(e=>"shape_mesh"===e.type||"asset_mesh"===e.type).filter(e=>null!=e.materialAssignments).flatMap(e=>e.materialAssignments).map(async t=>{const a=this.assets.get(t.materialId);if(null!=a)for(const t of Object.values(a.material.shaderParams??{}))if(t.type===Xe.Texture&&"string"==typeof t.value){const a=this.assets.get(t.value),s=await this.assetManagerService.getTexture(a);null!=s&&e.push(s)}})),0!==e.length&&this.renderingView){console.log(`Initializing ${e.length} textures`),console.time("Init textures");for(const t of e)this.renderingView.renderer.initTexture(t);console.timeEnd("Init textures")}}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter(e=>null!=e.assetId&&"asset_mesh"==e.type).filter(e=>e.assetId)));await Promise.all(e.map(e=>this.assetsService.getAsset(e.assetId).then(e=>{if(null!=e)return this.assetManagerService.getMesh(e)}))),this.initTextures()}async init(){await this.preInit(),xt.clear(),It.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map(e=>this.materialize(e))),await this.initActorsPostInit()}async initVfx(){console.time("Init VFX");const e=new Set,t=[],a=new b;for(const s of this.actorInstances){const r=ta(s);for(const s of r){const r=s.asset;if(e.has(r.id))continue;e.add(r.id),r.vfx.emitters;const i=await s.create(a);a.add(i.object),a.add(i.particleSystemContainer),i.play(),i.onUpdate(.5),i.stop(),i.pause(),t.push(i)}}const s=this.renderingView.compileAsync(a);this.renderingView.initTextures(a),await s;for(const e of t)e.onEndPlay(),e.disposed.next(!0),e.object.removeFromParent();console.timeEnd("Init VFX")}async initActorsPostInit(e=Array.from(this.materializedActors.entries())){const t=e.map(async([e,t])=>{const a=t.object.userData.src??t.object.userData._src;if("vfx"===a.type)return Promise.resolve();const s=await this.assetsService.getAsset(a.assetId),r=e.split("/"),i=r.slice(0,-1),n=i.join("/"),o=(r[r.length-1],new Map);for(const[e,t]of this.materializedActors)if(o.set(e,t),0===n.length)e.includes("/")||o.set(e,t);else if(e.startsWith(n+"/")){const a=e.slice(n.length+1);a.includes("/")||o.set(a,t)}const l={...s?.actor?.params??{},...a.actor?.params??{}},c=[...a.actor?.innerParams??[]];for(let t=i.length-1;t>=0;t--){const a=i.slice(0,t+1).join("/"),s=this.idToSceneObject.get(a);if("prefab"===s?.type&&null!=s.prefab){const i=await this.assetsService.getAsset(s.assetId);if(null!=i){let n=!1,o=a+"/"+i.prefab?.mainActorId;for(;null!=o;){if(o===e){n=!0;break}o=this.prefabInstanceExposedActorMap.get(o)}if(n&&null!=s.prefab.params&&Object.assign(l,zt(s.prefab.params)),null!=s.prefab.innerParams)for(const e of s.prefab.innerParams){const a=r.slice(t+1);e.path.length>=a.length&&e.path.slice(0,a.length).every((e,t)=>e===a[t])&&c.push({path:e.path.slice(a.length),params:e.params})}}}}for(const e of c)await this.applyActorComponentParams(t,e.path.slice(),e.params,o);await this.attachEditorComponents(t,a,o);const h=await prepareClassParameters(l,t.constructor,this.assetsService,this.assetManagerService,o,this.renderingView,this.shaders,this.actorProvider,e=>{const t=n.length>0?n+"/"+e:e;return this.prefabInstanceExposedActorMap.get(t)??null});Object.assign(t,h);try{return await this.actorProvider.initActor(t)}catch(e){console.error(`Failed to initiate actor (name="${a.name}", id=${a.id})`,e)}});return Promise.all(t)}async attachEditorComponents(e,t,a){const s=t.actor?.components??[];for(const r of s){const s=this.componentTypes.find(e=>e.name===r.type);if(null==s){console.warn(`Component type '${r.type}' not found for actor ${t.id}`);continue}const i=e.attach(s.type);if(null!=r.params){const e=await prepareClassParameters(r.params,null,this.assetsService,this.assetManagerService,a,this.renderingView,this.shaders,this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);Object.assign(i,e)}for(const e of r.innerParams??[])await this.applyActorComponentParams(i,e.path.slice(),e.params,a)}}addVfxChildActors(e,t=e){}async applyActorComponentParams(e,t,a,s){const r=t.length,i=t.shift();if(0==r){const t=await prepareClassParameters(a,null,this.assetsService,this.assetManagerService,s,this.renderingView,this.shaders,this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[i]&&await this.applyActorComponentParams(e[i],t,a,s)}canObjectBeInstanced(e){return e.physics?.type!==ue.dynamic&&"sky"!==e.type&&"global_fog"!==e.type&&"world_env"!==e.type}async canAssetBeInstanced(e){let t=this._canBeInstancedCache.get(e.assetId);if(null==t){const a=await this.createFromAsset(e);if(null==a)return!1;const s=[];a.traverse(e=>{!Be(e)&&e.isMesh&&s.push(e)});const r=1==s.length&&0==s[0].children.length,i=!bt,n=s.every(e=>!Array.isArray(e.material)||1===e.material.length),o=s.some(e=>e instanceof m&&null!=e.geometry.morphAttributes&&Object.keys(e.geometry.morphAttributes).length>0),l=!0;t=s.length>0&&(r||n&&i)&&l&&!o,this._canBeInstancedCache.set(e.assetId,t)}return t}async preInit(){this.renderingView?.onLoop(()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)}),this.assetsService.getAssets().then(e=>{for(const t of e)this.assets.set(t.id,t)})}shouldBeMaterialized(e){if(!1===e.enabled)return!1;if(null!=this.detailTier&&"asset_mesh"===e.type&&null!=e.assetId){const t=this.assets.get(e.assetId);if(null!=t){const e=t.mesh?.detailTier;if(null!=e)return e<=this.detailTier}}return!0}async initWithInstancing(){await this.preInit(),await this.prefetchAssets(),xt.clear(),It.clear();const e=[],t=new je,a=new je,s=new je;let r=0,n=0,c=0;const h=new Map,p=new De(()=>new Map);for(const i of this.dataProvider.getObjects())await Vt(i,async(i,l,u)=>{if(!this.shouldBeMaterialized(i))return;const d="asset_mesh"==i.type&&this.canObjectBeInstanced(i)&&await this.canAssetBeInstanced(i),f="shape_mesh"===i.type&&"landscape"!==i.shape&&i.physics?.type!==ue.dynamic;if(d||f){if(l&&l.children?.length>0){const e=l.children.findIndex(e=>e.id===i.id);e>=0&&l.children.splice(e,1)}if(f){let e=i.shape+JSON.stringify(i.shapeParams??{})+i.castShadow+i.receiveShadow;const t=i.materialAssignments?.at(0)?.materialId,a=null!=t?this.assets.get(t):null;let r=null;if(!1&&null!=a&&"shader"!==a.material.type){if(e+=a.material.type+a.material.shader,null!=a.material.shaderParams){if(e+=Object.entries(a.material.shaderParams).filter(([e,t])=>"color"!=e).map(e=>JSON.stringify(e)).join(),null!=a.material.shaderParams.color){const e=a.material.shaderParams.color;e.type===Xe.Color&&null!=e.value&&(r=new o(e.value))}}e+=a.material.outlines,null!=a.material.outlineParams&&(e+=JSON.stringify(a.material.outlineParams)),e+=a.material.reflective,e+=a.material.bloom,e+=a.material.side,e+=a.material.side,e+=a.material.transparent,e+=a.material.alphaTest}else e+=t;s.push(e,{object:{...i,parentTransform:u},color:r}),c++}else{const e=this.assets.get(i.assetId);let s=h.get(i.assetId);if(null==s){const e=await this.createFromAsset(i,{assignMaterials:!1});if(null==e)return;if(s=h.get(i.assetId),null==s){s={useBatchedMesh:null!=Ve(e)&>(e,e=>!(e instanceof m)||this.testCanBatch(e.material,e.geometry)),assetMesh:e},h.set(i.assetId,s)}}const o=Nt(i.materialAssignments,e.materialAssignments);if(s.useBatchedMesh)await Oe(s.assetMesh,async e=>{if(!(e instanceof m))return;const t=Array.isArray(e.material)?e.material[0]:e.material,s=await this.resolveMaterialForAssignments(t,o);if(null!=s){p.get(i.id).set(e.uuid,s),aa(e.geometry,s);let t=Jt(s);t+=qt(e),a.push(t,{...i,parentTransform:u,meshUUID:e.uuid}),r++}else console.warn("Can not materialize mesh because missing material",i)});else{const e=i.assetId+JSON.stringify(i.materialAssignments??[]);t.push(e,{...i,parentTransform:u}),n++}}}else null==l&&e.push({...i,parentTransform:u})});console.log(`Scene init stats: \n Batched Assets: ${a.size} groups containing in total ${r} objects.\n Instanced Assets: ${t.size} groups containing in total ${n} objects.\n Shapes: ${s.size} batch groups containing in total ${c} objects. \n ${e.length} objects can not be batched. \n `);for(const e of h.values())this.prepareCollisionShapesForInstanced(e.assetMesh);console.time("materialize batches");for(const[e,t]of a.entries()){if(0==t.length)continue;let e;const a=h.get(t[0].assetId).assetMesh;e=this.createBatchedMesh(t,p,h);const s=this.assets.get(t[0].assetId);e.castShadow=t[0].castShadow??s.castShadow??!0,e.receiveShadow=t[0].receiveShadow??s.receiveShadow??!0;const r=new ze;r.add(e),r.userData.src=t[0],a instanceof ze&&(r.collisionShapes=a.collisionShapes),r.castShadow=!1,r.receiveShadow=!1,this.scene.add(r)}for(const e of t.values()){if(0==e.length)continue;let t;const a=h.get(e[0].assetId).assetMesh;t=await this.createInstancedMesh(e,a);const s=this.assets.get(e[0].assetId);t.castShadow=e[0].castShadow??s.castShadow??!0,t.receiveShadow=e[0].receiveShadow??s.receiveShadow??!0;const r=new ze;r.add(t),r.userData.src=e[0],a instanceof ze&&(r.collisionShapes=a.collisionShapes),this.prepareCollisionShapesForInstanced(r),r.castShadow=!1,r.receiveShadow=!1,this.scene.add(r)}console.timeEnd("materialize batches");for(const e of s.values()){if(0==e.length)continue;const t=e[0].object,a=await this.createFromShape(t),s=ke(a,e=>!Be(e)&&null!=e.geometry),r=s.material.clone();null!=e[0].color&&null!=r.color&&(r.color=new o(16777215));const n=s.geometry;let c,h;!(bt||r instanceof _||null==n.index)?(c=new i.BatchedMesh(e.length,n.getAttribute("position").count,n.index.count,r),c.perObjectFrustumCulled=!0,h=c.addGeometry(n)):c=new i.InstancedMesh(n,r,e.length),c.castShadow=a.castShadow??!0,c.receiveShadow=s.receiveShadow??!0;for(let t=0;t<e.length;t++){const a=e[t],s=(new i.Matrix4).compose((new x).fromArray(a.object.position),(new v).setFromEuler((new l).fromArray(a.object.rotation)),(new x).fromArray(a.object.scale)),r=(new d).copy(a.object.parentTransform).multiply(s);let n;n=c instanceof i.BatchedMesh?c.addInstance(h):t,c.setMatrixAt(n,r),a.color}for(let t=0;t<e.length;t++){const s=e[t],r=new ze;r.userData.src=e[0],a instanceof Ue&&(r.collisionShapes=[a.collisionShape]),r.castShadow=!1,r.receiveShadow=!1,this.scene.add(r),r.add(c),null==c.userData.hasCollision&&(c.userData.hasCollision=[]),c.userData.hasCollision[t]=!!s.object.collisionDetection}}await Promise.all(e.map(e=>this.materialize(e))),await this.initActorsPostInit(),await this.initVfx()}prepareCollisionShapesForInstanced(e){e instanceof ze&&e.collisionShapes.forEach(e=>{e instanceof a&&e.mesh instanceof m&&(e.mesh=e.mesh.geometry)})}testCanBatch(e,t){return!bt&&(!Array.isArray(e)||1==e.length)&&this.testCanBatchMaterial(e)}testCanBatchMaterial(e){const t=Array.isArray(e)?e[0]:e;return null!=t&&(!(t instanceof y)||null==t.bumpMap&&null==t.lightMap&&null==t.displacementMap)}createBatchedMesh(e,t,a){const s=new je;for(const t of e)null!=t.meshUUID?s.push(t.meshUUID??t.assetId,t):console.warn("Missing mesh uuid for batching");let r=0,n=0,l=0;const c=new Map;for(const[e,t]of s.entries()){const s=t[0].assetId,i=a.get(s);if(null==i){console.warn("Missing batching info for asset id "+s);continue}const o=ke(i.assetMesh,t=>t instanceof m&&t.uuid===e);if(null==o){console.warn("Missing mesh in batched asset");continue}c.set(e,o);const h=o.geometry.getAttribute("position");null==h&&console.warn("Missing position attribute for batched mesh"),r+=o.geometry.index.count*t.length,n+=h.count*t.length,l+=t.length}const h=["color","map","roughness","roughnessMap","metalness","metalnessMap","opacity","alphaMap","aoMap","aoMapIntensity","normalMap","normalScale","emissive","emissiveIntensity","emissiveMap"];let p=new Map;const u=[];let d=new i.MeshStandardMaterial({color:"white"});const f=t.get(e[0].id).get(e[0].meshUUID);if(null==f)throw"missing source material";if(f instanceof y&&!(f instanceof i.MeshPhysicalMaterial)){const a=new Set,s=new Map;for(const r of e){const e=t.get(r.id).get(r.meshUUID);if(null==e)throw"missing mat";for(const t of h){let r=e[t];r instanceof i.CompressedArrayTexture&&null!=r.userData.index&&(r=r.userData.index);const n=s.get(t);void 0===n||ea(r,n)?s.set(t,r):a.add(t)}}for(const e of a){let t;const a=f[e];if("number"==typeof a){let a=u.find(e=>e.params.length<4);if(null==a){const t="vp"+u.length;a={name:t,params:[e],node:T(t)},u.push(a)}else a.params.push(e);t=Kt(a.node,a.params.length-1)}else if(a instanceof I)t=T(e);else if(a instanceof x||a instanceof o)t=C(e);else if(a instanceof S)t=P(e);else if(a instanceof i.CompressedArrayTexture)t=D(e+"_i");else if(a instanceof A)continue;p.set(e,t)}let r=Y.uv;f instanceof mt&&null!=f.heightMap&&(r=ft(r,G(f.heightMap),z(f.heightScale)));let n=Ht(p.get("opacity"),F)??z(f.opacity??1);if(null!=f.alphaMap){let e;if(f.alphaMap instanceof i.CompressedArrayTexture){const t=J(f.alphaMap),a=Ht(p.get("alphaMap"),F)??z(f.alphaMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.alphaMap).sample(r);n=n.multiply(e.r)}let l=$(Ht(p.get("color"),te)??f.color,n);if(null!=f.map){let e;if(f.map instanceof i.CompressedArrayTexture){const t=J(f.map),a=Ht(p.get("map"),F)??z(f.map.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.map).sample(r);l=l.multiply(e),n=n.multiply(e.a)}f.vertexColors&&(l=l.multiply(ae(X(j.color.rgb),1)));let c=$(Ht(p.get("emissive"),te)??f.emissive,n);if(null!=f.emissiveMap){let e;if(f.emissiveMap instanceof i.CompressedArrayTexture){const t=J(f.emissiveMap),a=Ht(p.get("emissiveMap"),F)??z(f.emissiveMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.emissiveMap).sample(r);c=c.multiply(e)}const m=Ht(p.get("emissiveIntensity"),F)??z(f.emissiveIntensity??1),g=Ht(p.get("normalScale"),Q)??K(f.normalScale??new S(1,1));let y=Z.normal;if(null!=f.normalMap){let e;if(f.normalMap instanceof i.CompressedArrayTexture){const t=J(f.normalMap),a=Ht(p.get("normalMap"),F)??z(f.normalMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.normalMap).sample(r);y=O(e.rgb,g.x)}let w=Ht(p.get("roughness"),F)??z(f.roughness??1);if(null!=f.roughnessMap){let e;if(f.roughnessMap instanceof i.CompressedArrayTexture){const t=J(f.roughnessMap),a=Ht(p.get("roughnessMap"),F)??z(f.roughnessMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.roughnessMap).sample(r);w=w.multiply(e.g)}let M=Ht(p.get("metalness"),F)??z(f.metalness??0);if(null!=f.metalnessMap){let e;if(f.metalnessMap instanceof i.CompressedArrayTexture){const t=J(f.metalnessMap),a=Ht(p.get("metalnessMap"),F)??z(f.metalnessMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.metalnessMap).sample(r);M=M.multiply(e.b)}let v=z(1);if(null!=f.aoMap){let e;if(f.aoMap instanceof i.CompressedArrayTexture){const t=J(f.aoMap),a=Ht(p.get("aoMap"),F)??z(f.aoMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.aoMap).sample(r);v=v.multiply(e.r)}const b=Ht(p.get("aoMapIntensity"),F)??z(f.aoMapIntensity??0);let E=y;!0!==f.userData.disableAO&&(E=N("DOUBLE_SIDED",E,e=>L(new V("gl_FrontFacing"),e,e.multiplyScalar(-1))));const k=new _({color:R({color:l,roughness:w,metalness:M,ambientOcclusion:v,ambientOcclusionIntensity:b,emissive:c,emissiveIntensity:m,normal:E}),normal:y,roughness:w,emissive:c.rgb,transparent:f.transparent,alphaTest:f.alphaTest,envMap:f.envMap,opacity:n});null!=f.envMap&&(k.uniforms.envMapIntensity={value:f.envMapIntensity},k.uniforms.envMapRotation={value:Zt(f.envMapRotation,f.envMap)}),k.envMap=f.envMap,k.side=f.side,d=k}else{d=f;for(const a of e){const e=t.get(a.id).get(a.meshUUID);if(e!=d){console.error(`Different materials in group for object ${a.id} and mesh uuid ${a.meshUUID}`,{objectMaterial:e,sourceMaterial:f});break}}}const g=new dt(l,n,r,d);for(const e of u)g.initUniform(e.name,4);for(const[e,t]of p.entries()){if(u.some(t=>t.params.includes(e)))continue;let a=1;t instanceof se||t instanceof te?a=4:t instanceof Q&&(a=2),g.initUniform(e,a,0)}for(const[e,r]of s.entries()){const s=r[0].assetId,n=c.get(e);if(null==n){console.error(`Missing single asset mesh for mesh uuid ${e} and asset id ${s}`);continue}if(null==n.geometry){console.error("Missing geometry on mesh mesh");continue}const l=g.addGeometry(n.geometry),h=a.get(s);if(null==h){console.warn("Missing batching info when configuring for asset id "+s);continue}const d=Ve(h.assetMesh)?.uuid===e,m=h.assetMesh instanceof ze&&d?h.assetMesh.collisionShapes:void 0,f=this.configureBatchedInstancedMesh(r,g,n,l,m);for(let e=0;e<f.length;e++){const a=r[e],s=f[e],n=t.get(a.id).get(a.meshUUID);for(const e of u){let t=Qt.set(0,0,0,0);for(let a=0;a<e.params.length;a++){const s=n[e.params[a]];"number"==typeof s&&t.setComponent(a,s)}g.setUniformAt(e.name,s,t)}for(let e of p.keys()){if(u.some(t=>t.params.includes(e)))continue;let t=n[e];if(t instanceof o&&(t=new x(t.r,t.g,t.b)),t instanceof i.CompressedArrayTexture)t=t.userData.index??0,e+="_i";else if(t instanceof A||null==t)continue;g.setUniformAt(e,s,t)}}}return g}async createInstancedMesh(e,t){const a=ke(t,e=>!Be(e)&&null!=e.geometry),s=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(t,Nt(e[0].materialAssignments,s.materialAssignments)),a.updateMatrix();const r=a.geometry.clone(),n=a.material;let o;if(o=new i.InstancedMesh(r,n,e.length),this.configureBatchedInstancedMesh(e,o,a),a.material instanceof u&&o.castShadow&&o.receiveShadow&&Array.isArray(n))for(const e of n);return o}configureBatchedInstancedMesh(e,t,a,s,r){const n=[];a.updateWorldMatrix(!0,!0);for(let o=0;o<e.length;o++){let c=o;t instanceof i.BatchedMesh&&(c=t.addInstance(s)),n.push(c);const h=(new i.Matrix4).compose((new x).fromArray(e[o].position),(new v).setFromEuler((new l).fromArray(e[o].rotation)),(new x).fromArray(e[o].scale)),p=(new d).copy(e[o].parentTransform).multiply(h).multiply(a.matrixWorld);t.setMatrixAt(c,p),null==t.userData.hasCollision&&(t.userData.hasCollision=[]),t.userData.hasCollision[c]=!!e[o].collisionDetection,null!=r&&(null==t.userData.collisionShapes&&(t.userData.collisionShapes=[]),t.userData.collisionShapes[c]=r)}return n}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("world_env"===e.type)this.resetWorldEnv(),this.worldEnvObj=null;else if("actor"==e.type||"vfx"===e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay()):console.warn("Failed to remove actor",e)}else"prefab"===e.type&&this.materializedActors.forEach((t,a)=>{a.startsWith(e.id)&&(t.disposed.next(!0),t.onEndPlay()),this.materializedActors.delete(a)});const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter(t=>t.object.userData.src?.id===e.id).forEach(e=>this.components.splice(this.components.indexOf(e,1))),this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))}),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex(t=>t.source.id===e.id);if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return Ee(this.scene,t=>t.userData.src?.assetId==e,e=>null!=e.userData.src)}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter(e=>"null"!==e.materialId).map(t=>this.applyMaterial(e,t)))}async applyMaterial(e,t){await applyMaterial(e,t,e=>{const t=this.assets.get(e);if(null!=t)try{return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}catch(e){console.error("Failed to apply material",e)}},this._originalMaterials)}async resolveMaterialForAssignments(e,t){let a=e,s=null,r=null;for(const e of t??[]){if(!$t(a,e,s,r))continue;const t=this.assets.get(e.materialId);if(null==t){console.warn("Missing material with id "+e.materialId);continue}const i=await materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!0);null!=i&&a.id!==i.id&&(s=s??Ut(a),r=r??a.name,a=i)}return a}unapplyMaterials(e){e.traverse(async e=>{if(e instanceof m)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material})}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(he));Ee(this.scene,e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type)).forEach(async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)})}updateComponents(e){this.componentTypes=e,Ee(this.scene,e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&(e.userData.src.actor?.components?.length??0)>0).forEach(async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)})}updateShaders(e){this.shaders=e;for(const[e,t]of xt.entries())t.userData.customShaderName&&xt.delete(e);this.landscapeManagers.forEach(t=>t.updateShaders(e)),Ee(this.scene,e=>!0).forEach(e=>{e.traverse(async e=>{if(e instanceof m)if(Array.isArray(e.material))for(let t=0;t<e.material.length;t++){const a=e.material[t].userData?.customShaderName;if(null!=a){const a=this.assets.get(e.material[t].userData.assetId);this.refreshMaterial(e,e.material[t],a,t)}}else{const t=e.material.userData?.customShaderName;if(null!=t){const t=this.assets.get(e.material.userData.assetId);this.refreshMaterial(e,e.material,t)}}})})}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);if("world_env"===e.type&&null!=this.worldEnvObj)return void this.updateWorldEnv(e);const t=this.sceneObjectMap.get(e.id);if(t){let s=!1;if(t.traverseAncestors(e=>{"_hology_transform_group"===e.name&&(s=!0)}),!s){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse(e=>{e instanceof m&&(e.material.wireframe=!0)}):t.traverse(e=>{e instanceof m&&(e.material.wireframe=!1)})}if("asset_mesh"===e.type&&t.userData.assetId!==e.assetId){this.remove(e);const t=await this.materializeAndInitActor(e);return void this.updated$.next({object:t,source:e})}if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);Nt(e.materialAssignments,a.materialAssignments).forEach(e=>this.applyMaterial(t,e))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(s||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type){if("point"==e.light.type){const a=t;a.color=new o(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0),a.userData.volumetricIntensity=e.light.point.volumetricIntensity}else if("spot"==e.light.type){const a=t;a.color=new o(e.light.spot.color),a.intensity=e.light.spot.intensity,a.decay=e.light.spot.decay,a.angle=e.light.spot.angle,a.penumbra=e.light.spot.penumbra,a.castShadow=e.light.spot.castShadow,a.distance=Math.max(e.light.spot.distance,0),a.userData.volumetricIntensity=e.light.spot.volumetricIntensity}else if("directional"===e.light.type)this.applyDirectionalLight(e.light.directional,e);else if("ambient"===e.light.type)this.applyDirectionalAmbientLight(t,e.light.ambient,e);else if("rectArea"===e.light.type){const a=t;a.color=new o(e.light.rectArea.color),a.intensity=e.light.rectArea.intensity,null!=e.scale&&(a.width=e.scale[0],a.height=e.scale[1]),a.children.forEach(e=>{e instanceof yt&&e.update()})}}else if("landscape"===e.shape){const a=this.landscapeManagers.find(t=>t.source.id===e.id).source.landscape.options.density!==e.landscape.options.density;if(this.inEditor&&a){this.remove(e);const t=await this.materializeAndInitActor(e);return void this.updated$.next({object:t,source:e})}this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(t=>{t.updateSource(e),t.queueRefreshScatter(this.renderingView.camera.position,!0,e=>!0)})}else if("global_fog"===e.type){const t=(this.scene.fog instanceof h?"density":"linear")!==e.fog.type;this.scene.fog=Et(e.fog),t&&(a=this.scene).traverse(e=>{if(e instanceof m){const t=e.material;t instanceof _&&(a.fog instanceof c?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof h&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}}),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.materializedActors.get(e.id);if(t instanceof ht){const a=await prepareClassParameters(e.actor.params,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,[],this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);return void Object.assign(t,a)}const a=this.editorActorParamSnapshot.get(e.id);null!=a&&a===JSON.stringify(e.actor)||s||(this.remove(e),await this.materializeAndInitActor(e))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof Ue&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}if("shape_mesh"===e.type&&"landscape"!==e.shape)St(t,e.castShadow,e.receiveShadow);else if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);if(null==a)return void console.error("Asset not found",e.assetId);const s=e.receiveShadow??!!a.receiveShadow,r=e.castShadow??!!a.castShadow;St(t,r,s)}e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a;this.renderingView.renderer.shadowMap.needsUpdate=!0}async materializeAndInitActor(e,t=this.findParent(e)){const a=await this.materialize(e,t),s=Array.from(this.materializedActors.entries()).filter(([t])=>t===e.id||t.startsWith(e.id+"/"));return await this.initActorsPostInit(s),a}findParent(e){const t=this.dataProvider.getObjects().flatMap(t=>t.id===e.id?null:Te(t,t=>t.children?.some(t=>t.id===e.id),()=>!0))[0];return null==t?this.scene:null!=t?Ee(this.scene,e=>e.userData?.src?.id===t.id,e=>null!=e.userData?.src)[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new o(this.scene.fog.color))}findMeshWithGeometry(e){let t;return e.traverse(e=>{e instanceof m&&e.geometry&&(t=e)}),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;let a=1;for(const t of e.vertexMaterials)a=Math.max(t.w.length,a);const s=Pe(e.vertexMaterials,e=>e.m);t.traverse(e=>{if(e instanceof m){if(null==e.geometry)return;if(Lt(Je(e,0,!1)),a>0){Lt(Je(e,0,!1))}}});const r=new Set;for(const[e,i]of s.entries()){const s=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let n=!1;if(null==s||null==s.geometry)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const o=Je(s,0,!0);Lt(o);for(const e of i)o.setX(e.i,e.w[0]??0),o.setY(e.i,e.w[1]??0),o.setZ(e.i,e.w[2]??0),o.setW(e.i,e.w[3]??0),n=!0;if(a>0){const e=Je(s,4,!0);Lt(e);for(const t of i)e.setX(t.i,t.w[4]??0),e.setY(t.i,t.w[5]??0),e.setZ(t.i,t.w[6]??0),e.setW(t.i,t.w[7]??0),e.needsUpdate=!0,n=!0}n&&r.add(e)}this.inEditor&&this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,e=>r.has(e.name)))}async materialize(e,t,a=!1,s){const r=this.getNestedActorId(e.id,s);if(this.idToSceneObject.set(r,e),!this.shouldBeMaterialized(e))return;let i,n;switch(e.type){case"asset_mesh":i=await this.createFromAsset(e);break;case"shape_mesh":i=await this.createFromShape(e);break;case"light":i=await this.createLight(e);break;case"particles":i=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Et(e.fog),this.fixFogColor(),i=new p;break;case"sky":this.sky=Qe(),this.updateSky(e),i=this.sky;break;case"world_env":this.updateWorldEnv(e),i=new p,this.worldEnvObj=i;break;case"actor":({object:i,actor:n}=await this.createFromActor(e,s));break;case"group":i=new p;break;case"prefab":i=await this.createFromPrefab(e,s,t);break;case"vfx":i=await this.createFromVfx(e,s);break;default:if(this.inEditor)throw new Error("unknown type "+e.type);console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version.`)}if(null!=i){if(e.name&&e.name.length>0&&(i.name=e.name),this.applyTransform(e,i),a?i.userData._src=e:i.userData.src=e,null!=n&&(i.userData.actor=n),this.inEditor,this.inEditor,this.objectMap.set(i.uuid,e),this.sceneObjectMap.set(e.id,i),e.physics?.type!==ue.dynamic||null==t||this.inEditor?null==t?this.scene.add(i):null==t||"actor"!==e.type||this.inEditor?t?.add(i):(t.add(i),this.scene?.attach(i),console.log(i)):(t.add(i),i.getWorldPosition(i.position),i.getWorldQuaternion(i.quaternion),i.getWorldScale(i.scale),this.scene?.attach(i)),null!=e.children&&await Promise.all(e.children?.map(e=>this.materialize(e,i,a))),this.inEditor||null!=t||"asset_mesh"!=e.type&&"shape_mesh"!==e.type&&"prefab"!==e.type&&"group"!==e.type||"landscape"===e.shape||null!=e.physics?.type&&e.physics.type==ue.dynamic||Tt(i),null!=this.renderingView)return this.renderingView.renderer.shadowMap.needsUpdate=!0,i;console.warn("RenderingView not found in materializer")}}applyTransform(e,t){null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)}updateWorldEnv(e){this.renderingView.aoPass.enabled=e.worldEnv.ao.enabled,this.renderingView.aoPass.blendIntensity=e.worldEnv.ao.blendIntensity,this.renderingView.aoPass.updateGtaoMaterial(e.worldEnv.ao);const t=e.worldEnv.toneMapping;null!=t&&(this.renderingView.baseToneMapping=t.mapping??0,this.renderingView.baseToneMappingExposure=t.exposure??1,this.renderingView.renderer.toneMapping=this.renderingView.baseToneMapping,this.renderingView.renderer.toneMappingExposure=this.renderingView.baseToneMappingExposure);const a=e.worldEnv.environment;null!=a&&null!=a.textureId?this.assetManagerService.getTexture(this.assets.get(a.textureId)).then(e=>{null==this.pmremGenerator&&(this.pmremGenerator=new i.PMREMGenerator(this.renderingView.renderer),this.pmremGenerator.compileEquirectangularShader()),this.pmremGeneratorResults.has(e)||this.pmremGeneratorResults.set(e,this.pmremGenerator.fromEquirectangular(e).texture);const t=this.pmremGeneratorResults.get(e);this.renderingView.scene.environment=t,this.renderingView.scene.environmentIntensity=a.intensity??1}):this.renderingView.scene.environment=null}resetWorldEnv(){this.renderingView.aoPass.enabled=!1,this.renderingView.aoPass.blendIntensity=1,this.renderingView.aoPass.output=0,this.renderingView.baseToneMapping=0,this.renderingView.baseToneMappingExposure=1,this.renderingView.renderer.toneMapping=this.renderingView.baseToneMapping,this.renderingView.renderer.toneMappingExposure=this.renderingView.baseToneMappingExposure}async updateSky(e){null!=this.sky&&(null==e?.sky?.materialId&&this.sky.material!==et?(this.sky.material=et,this.applySkySettings(this.sky.material)):this.sky.material.userData?.assetId!==e.sky.materialId&&this.updateSkyMaterial(e),null!=e.rotation&&this.sky.rotation.fromArray(e.rotation))}async updateSkyMaterial(e){const t=await this.assetsService.getAsset(e.sky.materialId);if(null==t)return void console.warn(`No material asset found for sky with id ${e.sky.materialId}`);const a=await materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);this.applySkySettings(a),null!=this.sky?this.sky.material=a:console.warn("No sky has been created")}applySkySettings(e){e.side=i.BackSide,(e instanceof y||e instanceof i.MeshBasicMaterial||e instanceof i.ShaderMaterial)&&(e.fog=!1),e.depthTest=!1}async createComponent(e,t,a,s){const r=new Mt[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e,t){const a=this.actorTypes.find(t=>t.name===e.actor?.type)?.type??he[e.actor?.type];if(null==a)return{object:null,actor:null};this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const s=await this.actorProvider.create(a,(new x).fromArray(e.position),(new l).fromArray(e.rotation),!0);return this.materializedActors.set(this.getNestedActorId(e.id,t),s),{object:s?.object,actor:s}}getNestedActorId(e,t){return null!=t?t.sceneObjectChain.join("/")+"/"+e:e}async createFromVfx(e,t){const a=await this.assetsService.getAsset(e.assetId);null==a&&console.error("Could not find asset",e);const s=await this.actorProvider.create(ie,(new x).fromArray(e.position),(new l).fromArray(e.rotation),!1);try{await s.fromAsset(a)}catch(e){return console.error("Failed to create VFX asset",e),null}return s.play(),this.materializedActors.set(this.getNestedActorId(e.id,t),s),null!=s&&(s.object.userData.actor=s),s?.object}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e),a.traverse(e=>{e instanceof m&&this._originalMaterials.set(e.id,e.material)});else{let s=new y({name:"Default",color:new o("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});!0===e.collider&&(s.opacity=.3,s.color.set(2517460),s.transparent=!0);const r=await this.createMeshByShape(e.shape,s,e.shapeParams);r.castShadow=e.castShadow??!0,r.receiveShadow=e.castShadow??!1,e.collisionDetection||(r.collisionShape=null),r.physics=e.physics,a=r,this._originalMaterials.set(a.id,r.material),a.traverse(e=>{})}return t||(await Promise.all((e.materialAssignments??[]).filter(e=>null!=e.materialId).map(e=>this.applyMaterial(a,e))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new p;const a=We(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new $e(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,t=>{(e.materialAssignments??[]).filter(e=>null!=e.materialId).forEach(e=>this.applyMaterial(t,e))});return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new Le(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach(e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()}),this.inEditor&&!a||setTimeout(()=>Re(r),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&Ze.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);if(!this.geometryCache.has(r)){const t=Ye[e].geometry(s);t.computeTangents(),this.geometryCache.set(r,t)}this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,Ye[e].collision(s));return new Ue(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e,t){const a=this.assets.get(e.assetId)??await this.assetsService.getAsset(e.assetId);if(null==a)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:s}=await this.assetManagerService.getMesh(a,{mergeGeomtries:!0});if(!1!==t?.assignMaterials)try{await Promise.all(Nt(e.materialAssignments,a.materialAssignments).map(e=>this.applyMaterial(s,e)))}catch(t){console.error("Failed to apply material"+t,e)}const r=e.receiveShadow??!!a.receiveShadow,i=e.castShadow??!!a.castShadow;return s.receiveShadow=r,St(s,i,r),e.collisionDetection||(s.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(s.physics=e.physics),this.applyVertexMaterials(e,s),s.traverse(e=>{e instanceof m&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&e.geometry.computeBoundsTree()}),s.userData.assetId=e.assetId,s}async createFromPrefab(e,t,a){const s=await this.assetsService.getAsset(e.assetId);if(null==s)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);null==t&&(t={sceneObjectChain:[]}),t.sceneObjectChain.push(e.id);const{object:r}=await this.createFromPrefabAsset(s,t,a,e);return t.sceneObjectChain.pop(),r}async createFromPrefabAsset(e,t,a,s,r=!0){const i=new p;null!=s&&this.applyTransform(s,i),null!=a&&a.add(i),await Promise.all(e.prefab.objects.filter(e=>"global_fog"!==e.type&&"world_env"!==e.type).map(e=>this.materialize(e,i,!0,structuredClone(t))));const n=t.sceneObjectChain.join("/"),o=Array.from(this.materializedActors.entries()).filter(([e,a])=>e.startsWith(n)&&e.split("/").length-1===t.sceneObjectChain.length);let l;if(o.forEach(e=>{}),null!=e.prefab?.mainActorId){const a=t.sceneObjectChain.join("/")+"/"+e.prefab.mainActorId;l=this.materializedActors.get(a)}r||await this.initActorsPostInit(o);const c=Array.from(this.materializedActors.entries()).filter(([e,t])=>e.startsWith(n)).map(([,e])=>e);if(null!=e.prefab?.mainActorId&&null!=s){const a=t.sceneObjectChain.join("/"),s=a+"/"+e.prefab.mainActorId;this.prefabInstanceExposedActorMap.set(a,s)}return{object:i,actors:c,mainActor:l}}async createParticleSystem(e){await this.assetsService.getAsset(e.assetId);return new w}async createLight(e){if("point"===e.light.type){const t=new M(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s)}return t}if("spot"===e.light.type){const t=new i.SpotLight(e.light.spot.color,e.light.spot.intensity,e.light.spot.distance,e.light.spot.angle,e.light.spot.penumbra,e.light.spot.decay);if(t.castShadow=e.light.spot.castShadow??!0,t.target=new w,t.target.position.set(0,-1,0),t.add(t.target),this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s),t.add(new i.SpotLightHelper(t))}return t}if("rectArea"===e.light.type){const t=new i.RectAreaLight(e.light.rectArea.color,e.light.rectArea.intensity,e.scale?e.scale[0]:1,e.scale?e.scale[1]:1);if(this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s);const r=new yt(t);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional,e),new p):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient,e),new p):void 0}applyDirectionalAmbientLight(e,t,a){const s=this.scene.children.find(e=>e.name===Ke);null!=s?(s.intensity=t.intensity,s.color.set(t.color),s.groundColor.set(t.color),s.userData.src=a,s.userData.volumetricIntensity=t.volumetricIntensity):console.warn("Couldn't find ambient light")}applyDirectionalLight(e,t){for(const a of this.renderingView.csm.lights)a.intensity=e.intensity,a.color.set(e.color),a.castShadow=e.castShadow,a.userData.src=t,a.userData.volumetricIntensity=e.volumetricIntensity;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.createAssetSubscription.unsubscribe(),this.materializedActors.forEach(e=>e.disposed.next(!0)),this.materializedActors.clear()}};At=e([re(),t("design:paramtypes",[b,Object,Ne,Fe,fe,Array,Array,Object,Array])],At);export{At as SceneMaterializer};function St(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse(e=>{e.castShadow=t,e.receiveShadow=a})}const xt=new Map,It=new Map,jt=new f({color:16711935}),Dt=new Map;export async function materialFromAsset(e,t,a,s,r,i=!0){const n=JSON.stringify(e.material)+t?._id;return i&&xt.has(n)?xt.get(n):i&&It.has(n)?await It.get(n):It.set(n,_materialFromAsset(n,e,t,a,s,r,i)).get(n)}export async function _materialFromAsset(e,t,a,r,n,l,c=!0){const h={opacity:t.material.params?.opacity??1,map:null,emissive:t.material.params?.emissive??null,metalness:t.material.params?.metalness??0,flatShading:t.material.params?.flatShading??!1,color:new o(t.material.params?.color),transparent:null!=t.material.params?.opacity&&t.material.params?.opacity<1},p={};if(null!=t.material.params?.map){const e=t.material.params.map,a=await r.getAsset(e);null!=a&&(h.map=await n.getTexture(a))}let u;switch(t.material.type){case"phong":u=new g({...h,...p});break;case"water":u=He(h,a);break;case"grassFoliage":u=qe({color:h.color,map:h.map},a);break;case"grass":u=Ge({...h,colorTwo:new o(t.material.params.colorTwo),colorThree:new o(t.material.params.colorThree)},a);break;case"standard":case"unlit":case"toon":case"layered":case"lambert":case"shader":case"landscape":case"landscape-composite":case"decal-unlit":case"decal-standard":case"sprite":const e={standard:vt?ve:Se,lambert:ve,unlit:xe,toon:ut,layered:lt,landscape:Ae,"landscape-composite":be,"decal-unlit":at,"decal-standard":st,sprite:s}[t.material.type]??l.find(e=>e.name==t.material.shader)?.type;if(e){try{let s=new e;const i=await prepareClassParameters(t.material?.shaderParams??{},e,r,n,null,a,l);Object.assign(s,i),u=s.build()}catch(e){console.log("Shader runtime error: "+e,e),Dt.has(t.material.shader)||Dt.set(t.material.shader,jt.clone()),u=Dt.get(t.material.shader)}u.userData.customShaderName=t.material.shader}else console.warn("Missing shader implementation with name "+t.material.shader),u=jt;break;default:throw new Error("Unsupported material type "+t.material.type)}return a?.csm.setupMaterial(u),null!=a&&xt.set(e,u),u.side=t.material.side??u.side??i.FrontSide,u.transparent=(t.material.transparent??h.transparent??!1)||u.transparent,u.alphaTest=t.material.alphaTest??u.alphaTest??0,null!=t.material.blending&&(u.blending=de[t.material.blending]??i.NormalBlending),t.material.bloom&&(u.userData.hasBloom=!0),t.material.reflective&&(u.userData.reflective=!0),!0===t.material.outlines&&(u.userData.outlineParameters={},null!=t.material.outlineParams&&(null!=t.material.outlineParams.color&&(u.userData.outlineParameters.color=new o(t.material.outlineParams.color).toArray()),null!=t.material.outlineParams.thickness&&(u.userData.outlineParameters.thickness=t.material.outlineParams.thickness))),u.userData.assetId=t.id,It.delete(e),u}export async function prepareClassParameters(e,t,a,s,r,i,n,o,l){const c={};for(const[t,h]of Object.entries(e)){if(!1===h.override)continue;const e=await Ct(t,h,a,s,r,i,n,o,void 0,void 0,l);null!=e&&(c[t]=e)}return c}export async function prepareShapeParameters(e,t,a){const s={};for(const[r,i]of Object.entries(e)){const e=await Ct(r,i,t,a,null,void 0,void 0,void 0,void 0,void 0);null!=e&&(s[r]=e)}return s}const Pt=new Map;async function Ct(e,t,a,s,r,i,n,c,h=t.value,p=t.type,u){if(null==t||null==h||""===h)return null;switch(p){case Xe.Array:if(Array.isArray(h)&&"element"in t)return await Promise.all(h.map(o=>Ct(e,t,a,s,r,i,n,c,o,t.element,u)));break;case Xe.Number:case Xe.FloatNode:let p;if("string"==typeof h?p=parseFloat(h):"number"==typeof h&&(p=h),t.type===Xe.FloatNode){if("object"==typeof h&&"a"in h&&"b"in h){const e=h;if(null==e.a)return null;const t="string"==typeof e.a?parseFloat(e.a):e.a;if(null==e.b)return t;const a="string"==typeof e.b?parseFloat(e.b):e.b,s=function(e){let t=Pt.get(e);return null==t&&(t=ge(tt.decode(e)),Pt.set(e,t)),t}(e.easing),r=s.sample(ye(we.energy));return B(z(t),z(a),r)}return z(p)}return p;case Xe.Texture:let d=await s.getTexture(await a.getAsset(h));return"envmap"===e.toLowerCase()&&null!=i&&(d=i.getEnvTexture(d)),d;case Xe.Sampler2DNode:const m=await a.getAsset(h);if(null!=m.texture?.textureArrayFileKey){const{texture:e,layerIndex:t}=await s.getTextureArray(m);if(e&&null!=t)return new H(null,e,z(t))}const f=await s.getTexture(m);return f?G(f):null;case Xe.Boolean:return h;case Xe.BooleanNode:return E(h);case Xe.Vector2:case Xe.Vec2Node:if("object"==typeof h){const e=h instanceof Array?(new S).fromArray(h):new S(h.x,h.y);return t.type===Xe.Vec2Node?K(e):e}return null;case Xe.Vector3:case Xe.Vec3Node:if("object"==typeof h){const e=h instanceof Array?(new x).fromArray(h):new x(h.x,h.y,h.z);return t.type===Xe.Vec3Node?ee(e):e}return null;case Xe.Color:case Xe.RgbNode:const g=new o(h);return t.type===Xe.RgbNode?U(g):g;case Xe.String:return h;case Xe.BaseActor:const y=h;if(null==r&&console.warn("Class parameters can not be prepared as actors are not passed in"),null==y)return null;if("object"==typeof y&&null!=y.type&&null!=y.id){if("actor"===y.type)return r?.get(y.id)??null;if("prefab"===y.type){const e=u?u(y.id):null;if(null!=e)return r?.get(e)??null;const t=[];for(const[e,a]of r?.entries()??[])e.startsWith(y.id+"/")&&t.push(a);return 1===t.length?t[0]:null}}if("string"==typeof y){const e=r?.get(y);if(null!=e)return e;const t=u?u(y):null;if(null!=t)return r?.get(t)??null;const a=[];for(const[e,t]of r?.entries()??[])e.startsWith(y+"/")&&a.push(t);return 1===a.length?a[0]:null}return null;case Xe.Euler:const w=h;return(new l).fromArray(w);case Xe.Object3D:{const e=await a.getAsset(h);return(await s.getMesh(e,{applyMaterials:!0})).scene}case Xe.Material:{if(null==h)return null;const e=await a.getAsset(h);return null==e?(console.warn("Material asset not found for material parameter",h),null):null==e.material?(console.warn("Using a non-material asset for material parameter"),null):await materialFromAsset(e,i,a,s,n)}case Xe.AudioBuffer:return await s.getAudio(await a.getAsset(h));case Xe.VisualEffect:const M=await a.getAsset(h);if(null==c){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in M)return new ne(c,M);console.error("Using a non-vfx asset for visual effect parameter");break;case Xe.Prefab:{const e=await a.getAsset(h);return null==e?(console.error("Using a non-prefab asset for prefab parameter",h),null):new oe(e)}case Xe.PrefabActor:{const e=await a.getAsset(h);return null==e?(console.error("Using a non-prefab asset for prefab parameter",h),null):new le(new oe(e))}case Xe.Sequence:{const e=await a.getAsset(h);if("sequence"===e.type&&"sequence"in e)return new wt(e.sequence);console.error("Using a non-sequence asset for sequence parameter");break}case Xe.Curve:return tt.decode(h);case Xe.ColorLayer:case Xe.MaskLayer:if(ct(h)){const e=await rt.decode(h,async e=>await s.getTexture(await a.getAsset(e))),t=await prepareClassParameters(h.params,null,a,s);return Object.assign(e,t),e}return console.warn("Expecting color layer but got",h),null;case Xe.AnimationClip:{const e="string"==typeof h?h:"object"==typeof h&&null!=h?h.assetId:null;if(null==e)return console.warn("Invalid animation clip asset id value",h),null;return await s.getAnimationClip(await a.getAsset(e))}}return null}function Tt(e){e.updateWorldMatrix(!0,!0),e.updateMatrix(),e.traverse(e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1});const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}function Et(e){return"linear"===e.type?new c(new o(e.color),e.near??100,e.far??1e3):"density"===e.type?new h(e.color,e.density):void console.warn("Invalid fog type",e)}new y({color:4229780});async function Vt(e,t,a,s){null==s&&(s=(new d).identity());const r=s.clone().multiply(kt(e,new i.Matrix4));if(null!=e.children&&e.children.length>0)for(let a=e.children.length-1;a>=0;a--)await Vt(e.children[a],t,e,r);await t(e,a,s)}function kt(e,t){return null==e.position||null==e.rotation||null==e.scale?t.identity():t.compose((new x).fromArray(e.position),(new v).setFromEuler((new l).fromArray(e.rotation)),(new x).fromArray(e.scale))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?Xe.Number:t instanceof F||"function"==typeof e.prototype.isFloat?Xe.FloatNode:t instanceof A||e===A||e.isTexture?Xe.Texture:t instanceof Me||e===q?Xe.Sampler2DNode:t instanceof Boolean||e===Boolean?Xe.Boolean:t instanceof k?Xe.BooleanNode:t instanceof o||e==o?Xe.Color:t instanceof W||"function"==typeof e.prototype.isRgb?Xe.RgbNode:t instanceof S||e==S?Xe.Vector2:t instanceof Q||"function"==typeof e.prototype.isVec2?Xe.Vec2Node:t instanceof x||e==x?Xe.Vector3:t instanceof te||"function"==typeof e.prototype.isVec3?Xe.Vec3Node:t instanceof String||e===String?Xe.String:t instanceof ce||e==ce||e.prototype instanceof ce||e.prototype==ce?Xe.BaseActor:t instanceof l||e==l?Xe.Euler:t instanceof w||e==w?Xe.Object3D:t instanceof u||e==u?Xe.Material:t instanceof AudioBuffer||e==AudioBuffer?Xe.AudioBuffer:t instanceof ne||e==ne?Xe.VisualEffect:t instanceof oe||e==oe?Xe.Prefab:t instanceof le||e==le?Xe.PrefabActor:t instanceof tt||e==tt?Xe.Curve:t instanceof rt||e==rt?Xe.ColorLayer:t instanceof ot||e==ot?Xe.MaskLayer:t instanceof i.AnimationClip||e==i.AnimationClip?Xe.AnimationClip:t instanceof wt||e==wt||"SequenceData"===e.name||e.prototype&&"tracks"in e.prototype?Xe.Sequence:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map(e=>{const s=e.options.array?Xe.Array:toSerializedParamType(e.type),r=e.options.array?toSerializedParamType(e.type):void 0,i=t[e.name];let n=i?.override;void 0===n&&null!=i&&!0===e.options.optional&&(n=!0),void 0===n&&!0===e.options.optional&&(n=!1);const o=function(e,t){if(void 0!==t[e.name])return t[e.name];if(void 0!==e.options.defaultValue){const t=serializeCustomParameter(e.type,e.options.defaultValue);return void 0!==t?t:e.options.defaultValue}return customParameterDefaultValueByType.get(toSerializedParamType(e.type))}(e,a),l=!1!==n||e.options.array?i?.value??(e.options.array?[]:Ft(o)):Ft(o);return[e.name,{type:s,...r?{element:r}:{},value:l,override:n}]}))}function Ot(e){return null!=e&&(!1!==e.override&&(!0===e.override||function(e){return null!=e&&(e.type===Xe.Array?Array.isArray(e.value)?e.value.length>0:null!=e.value:null!=e.value&&""!==e.value)}(e)))}function zt(e){return null==e?{}:Object.fromEntries(Object.entries(e).filter(([,e])=>Ot(e)))}export function prepareCustomParamsFromType(e,t,a=null){const s=Ie(e);if(0===s.length)return{};let r;null!=a?me(a,()=>{r=a.get(e)}):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t&&!0!==e.options.array){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}function Ft(e){return null==e?e:Array.isArray(e)?e.map(e=>Ft(e)):"object"==typeof e?"function"==typeof structuredClone?structuredClone(e):JSON.parse(JSON.stringify(e)):e}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case S:return t instanceof S?t.toArray():void a();case x:return t instanceof x?t.toArray():void a();case I:return t instanceof I?t.toArray():void a();case o:return t instanceof o?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new o(t).getHexString():void a();case String:return t;case l:return t instanceof l?t.toArray():void a();case oe:return t instanceof oe?t.asset?.id??null:void a()}if(t&&"object"==typeof t&&"tracks"in t&&"duration"in t)return t}function Nt(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter(e=>Bt(e.materialId)),(t??[]).filter(e=>Bt(e.materialId)),e=>e.color+e.name)}function Bt(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[Xe.RgbNode,"#000000"],[Xe.Color,"#000000"],[Xe.Vector4,[0,0,0,0]],[Xe.Vec4Node,[0,0,0,0]],[Xe.Vector3,[0,0,0]],[Xe.Vec3Node,[0,0,0]],[Xe.Vector2,[0,0]],[Xe.Vec2Node,[0,0]],[Xe.Euler,[0,0,0,"XYZ"]],[Xe.Array,[]],[Xe.ColorLayer,it],[Xe.MaskLayer,nt]]);let _t=new o;new o;function Ut(e){return null==e?.color?null:(_t.set(e.color),"#"+_t.getHexString())}function $t(e,t,a,s){const r=Ut(e);return null!=r&&(r===t.color&&(e.name===t.name||null==t.name)||a===t.color&&s===t.name)}export function applyMaterial(e,t,a,s){const r=[];return e.traverse(async e=>{if(e instanceof m||e.isMesh||e instanceof i.SkinnedMesh||e.isSkinnedMesh)for(const t of Ce(e.material))t.hasOwnProperty("color")&&r.push(e)}),Promise.all(r.map(async e=>{if(e.material instanceof Array)for(let r=0;r<e.material.length;r++){const i=e.material[r];if(null==i.color||!(i.color instanceof o))continue;const n=Ut(i),l=i.name;if($t(i,t,e.userData["originalColor_"+r],e.userData["originalMaterialName_"+r])){const i=await a(t.materialId),o=e.material[r];null!=i&&o.id!=i.id&&(e.material[r]=i,e.userData["originalColor_"+r]=e.userData["originalColor_"+r]??n,e.userData["originalMaterialName_"+r]=e.userData["originalMaterialName_"+r]??l,null!=s&&s.set(e.id+"#"+r,o))}}else if("color"in e.material){const r=e.material,i=Ut(r),n=r.name;if($t(r,t,e.userData.originalColor,e.userData.originalMaterialName)){const r=await a(t.materialId),o=e.material;null!=r&&(e.material=r,e.userData.originalColor=e.userData.originalColor??i,e.userData.originalMaterialName=e.userData.originalMaterialName??n,null!=s&&(s.has(e.id)||s.set(e.id,o)))}}}))}function Wt(e,t){if(e instanceof i.ShaderMaterial&&t instanceof i.ShaderMaterial){return e.fragmentShader+e.vertexShader==t.fragmentShader+t.vertexShader&&function(e,t){if(e instanceof i.ShaderMaterial&&t instanceof i.ShaderMaterial){for(const a in e.uniforms){if(null==t.uniforms[a])return!1;if(t.uniforms[a].value!==e.uniforms[a].value)return!1}return!0}return!1}(e,t)}return!1}function Lt(e){if(null!=e){for(let t=0;t<e.array.length;t++)e.setX(t,0);e.needsUpdate=!0}}const Rt=new WeakMap;function qt(e){let t=Rt.get(e);return null==t&&(t=function(e){const t=Ve(e);if(null==t)return"";return Object.keys(t.geometry.attributes).sort().join(",")}(e),Rt.set(e,t)),t}const Gt=new WeakMap;function Jt(e){let t=Gt.get(e);return null==t&&(t=function(e){let t=e.type;e instanceof i.MeshStandardMaterial&&!(e instanceof i.MeshPhysicalMaterial)||(t+=e.id+"");(e instanceof i.MeshBasicMaterial||e instanceof i.MeshLambertMaterial||e instanceof y||e instanceof g)&&(null!=e.map&&(t+="c"+e.map?.id),null!=e.aoMap&&(t+="o"+e.aoMap?.id),null!=e.lightMap&&(t+="l"+e.lightMap?.id),null!=e.envMap&&(t+="v"+e.envMap?.id),null!=e.alphaMap&&(t+="a"+e.alphaMap?.id));e instanceof y&&(null!=e.normalMap&&(t+="n"+e.normalMap?.id),null!=e.roughnessMap&&(t+="r"+e.roughnessMap?.id),null!=e.metalnessMap&&(t+="m"+e.metalnessMap?.id),null!=e.emissiveMap&&(t+="e"+e.emissiveMap?.id));e instanceof i.MeshPhysicalMaterial&&(null!=e.sheenColorMap&&(t+="sc"+e.sheenColorMap?.id),null!=e.sheenRoughnessMap&&(t+="sr"+e.sheenRoughnessMap?.id));(e instanceof f||e instanceof g)&&null!=e.specularMap&&(t+="s"+e.specularMap?.id);e instanceof i.MeshToonMaterial&&(null!=e.map&&(t+="c"+e.map?.id),null!=e.aoMap&&(t+="o"+e.aoMap?.id),null!=e.lightMap&&(t+="l"+e.lightMap?.id),null!=e.alphaMap&&(t+="a"+e.alphaMap?.id));e instanceof mt&&null!=e.heightMap&&(t+="h"+e.heightMap?.id);if(e instanceof i.ShaderMaterial){t+=e.vertexShader,t+=e.fragmentShader;for(const a in e.uniforms){const s=e.uniforms[a];s&&s.value&&s.value.isTexture&&null!=s.value.id&&(t+="t:"+a+":"+s.value.id)}}null!=e.userData.outlineParameters&&(t+=e.userData.outlineParameters.color,t+=e.userData.outlineParameters.thickness);return t+=e.side,t+=e.transparent?"t":"",t+=e.vertexColors?"vc":"",t+=e.depthWrite?"dw":"",t+=e.depthTest?"dt":"",t+=e.alphaTest?"at":"",t}(e),Gt.set(e,t)),t}function Ht(e,t){if(null==e)return null;if(!(e instanceof t))throw new Error(`Value is not an instance of ${t.name}`);return e}const Xt=new d,Yt=new l;function Zt(e,t){return Yt.copy(e),Yt.x*=-1,Yt.y*=-1,Yt.z*=-1,t.isCubeTexture&&!1===t.isRenderTargetTexture&&(Yt.y*=-1,Yt.z*=-1),(new i.Matrix3).setFromMatrix4(Xt.makeRotationFromEuler(Yt))}function Kt(e,t){switch(t){case 0:return e.x;case 1:return e.y;case 2:return e.z;case 3:return e.w}}const Qt=new I;function ea(e,t){return e===t||null==e==(null==t)&&("number"==typeof e&&"number"==typeof t?e===t||isNaN(e)&&isNaN(t):e instanceof i.Color&&t instanceof i.Color?e.r===t.r&&e.g===t.g&&e.b===t.b:e instanceof S&&t instanceof S?e.x===t.x&&e.y===t.y:e instanceof x&&t instanceof x?e.x===t.x&&e.y===t.y&&e.z===t.z:e instanceof I&&t instanceof I&&(e.x===t.x&&e.y===t.y&&e.z===t.z&&e.w===t.w))}function ta(e){const t=[];for(const[a,s]of Object.entries(e))s instanceof ne?t.push(s):s instanceof pe&&t.push(...ta(s));return t}function aa(e,t){if(!(t instanceof i.ShaderMaterial)){if(e.deleteAttribute("uv1"),e.hasAttribute("color")){const t=e.getAttribute("color");let a=!0;for(let e=0;e<t.count;e++)for(let s=0;s<3;s++){if(1!=t.getComponent(e,s)){a=!1;break}}a&&e.deleteAttribute("color")}if(e.hasAttribute("uv2")){null!=t.lightMap&&null!=t.aoMap||e.deleteAttribute("uv2")}}}function sa(e,t,a){if(t(e))return e;for(const s of e.children??[]){const e=sa(s,t,a);if(null!=e)return e}if(null!=a&&"prefab"===e.type){const s=a.get(e.assetId);if(null!=s){const e=s.prefab.objects.find(e=>sa(e,t,a));if(null!=e)return e}}return null}/*
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{ConvexPolyhedronCollisionShape as a,SpriteShader as s}from"@hology/core";import{Subject as r}from"rxjs";import*as i from"three";import{BoxGeometry as n,Color as o,Euler as l,Fog as c,FogExp2 as h,Group as p,Material as u,Matrix4 as d,Mesh as m,MeshLambertMaterial as f,MeshPhongMaterial as g,MeshStandardMaterial as y,Object3D as w,PointLight as M,Quaternion as v,Scene as b,Texture as A,Vector2 as S,Vector3 as x,Vector4 as I}from"three";import{attributes as j,batchingUniformFloat as D,batchingUniformVec2 as P,batchingUniformVec3 as C,batchingUniformVec4 as T,bool as E,BooleanExpression as V,BooleanNode as k,colorToNormal as O,float as z,FloatNode as F,ifDefApply as N,mix as B,NodeShaderMaterial as _,rgb as U,rgba as $,RgbNode as W,select as L,standardMaterial as R,Texture2dLookupNode as q,textureSampler2d as G,textureSampler2dArray as J,UniformSampler2dArraySlice as H,varying as X,varyingAttributes as Y,varyingTransformed as Z,vec2 as K,Vec2Node as Q,vec3 as ee,Vec3Node as te,vec4 as ae,Vec4Node as se}from"three-shader-graph";import{Service as re}from"typedi";import{VfxActor as ie}from"../effects/vfx/vfx-actor.js";import{VisualEffect as ne}from"../effects/vfx/vfx-param.js";import{Prefab as oe,PrefabOf as le}from"./objects/prefab.js";import{BaseActor as ce}from"../gameplay/actors/actor.js";import he from"../gameplay/actors/builtin/index.js";import{ActorComponent as pe}from"../gameplay/actors/component.js";import{PhysicsBodyType as ue}from"../gameplay/services/physics/physics-system.js";import{ThreeBlendingMode as de}from"../effects/vfx/vfx-asset.js";import{withInjectionContext as me}from"../gameplay/inject.js";import{RenderingView as fe}from"../rendering.js";import{curveSampler as ge,oneMinus as ye,particleUniforms as we,Sampler2DNode as Me}from"../shader-nodes/index.js";import{LambertShader as ve}from"../shader/builtin/lambert-shader.js";import{LandscapeCompositeShader as be}from"../shader/builtin/landscape-composite-shader";import{LandscapeShader as Ae}from"../shader/builtin/landscape-shader.js";import{StandardShader as Se}from"../shader/builtin/standard-shader.js";import{UnlitShader as xe}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as Ie}from"../shader/parameter.js";import{ArrayMap as je,DefaultMap as De,groupBy as Pe}from"../utils/collections.js";import{iterateMaterials as Ce}from"../utils/materials.js";import{filterChildrenShallow as Te,filterSceneShallow as Ee,findFirstVisibleMesh as Ve,findFirstVisibleObject as ke,traverseAsync as Oe}from"../utils/three/traverse.js";import{AssetMeshInstance as ze,AssetResourceLoader as Fe}from"./asset-resource-loader.js";import{AssetsProvider as Ne}from"./assets-provider.js";import{isCollisionMesh as Be}from"./collision/collision-shape-import.js";import{BoxCollisionShape as _e,PhysicalShapeMesh as Ue}from"./collision/collision-shape.js";import{LandscapeManager as $e}from"./landscape/landscape-manager.js";import{initLandscape as We}from"./landscape/landscape.js";import{SectionGrid as Le,smoothNormalsCrossMeshes as Re}from"./landscape/utils.js";import{createGrassFoliageMaterial as qe}from"./materials/grass-foliage.js";import{createGrassMaterial as Ge}from"./materials/grass.js";import{getMaterialAttribute as Je}from"./materials/utils/material-painting.js";import{createWaterMaterial as He}from"./materials/water.js";import{SerializedParamType as Xe}from"./model.js";import{ShapeLibrary as Ye,ShapeLibraryKeys as Ze}from"./objects/shapes.js";import{ambientLightName as Ke,createSky as Qe,defaultSkyMaterial as et}from"./sky.js";import{Curve2 as tt}from"../utils/curve.js";import{DecalUnlitShader as at}from"../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as st}from"../shader/builtin/decal-standard-shader.js";import{ColorLayer as rt,defaultValueColorLayer as it,defaultValueMaskLayer as nt,MaskLayer as ot}from"../shader/color-layer.js";import{LayeredShader as lt}from"../shader/builtin/layered-shader";import{isColorLayerSerialized as ct}from"../shader/color-layer";import{FogVolume as ht}from"../rendering/fog/fog-volume-actor.js";import{UnscaledSprite as pt}from"../utils/three/unscaled-sprite.js";import{ToonShader as ut}from"../shader/builtin/toon-shader.js";import{BatchedMesh2 as dt}from"./batched-mesh-2.js";import{ParallaxStandardMaterial as mt}from"../shader/builtin/standard-shader";import{parallaxOcclusionMapping as ft}from"../shader-nodes/pom.js";import{traverseVisibleEvery as gt}from"../utils/three/traverse";import{RectAreaLightHelper as yt}from"three/examples/jsm/Addons.js";import{Sequence as wt}from"../effects/sequence/sequence-data.js";const Mt={},vt=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),bt=/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(navigator.userAgent.includes("iPhone")||navigator.userAgent.includes("iPad"))&&!!navigator.userAgent.match(/AppleWebKit/)&&!navigator.userAgent.match(/CriOS/);export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new At(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}let At=class{constructor(e,t,a,s,n,o,l,c,h=[]){this.scene=e,this.dataProvider=t,this.assetsService=a,this.assetManagerService=s,this.renderingView=n,this.shaders=o,this.actorTypes=l,this.actorProvider=c,this.componentTypes=h,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.idToSceneObject=new Map,this.inEditor=!0,this.updated$=new r,this.removed$=new r,this.error$=new r,this.editorActorParamSnapshot=new Map,this.assets=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.pmremGeneratorResults=new WeakMap,this.prefabInstanceChain=[],this.prefabInstanceExposedActorMap=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.assetManagerService.materialProvider=async e=>materialFromAsset(this.assets.get(e)??await this.assetsService.getAsset(e),this.renderingView,this.assetsService,this.assetManagerService,this.shaders),this.originalFog=null,t.onCreate(e=>this.update(e)),t.onUpdate(e=>this.update(e)),t.onRemove(e=>this.remove(e)),this.createAssetSubscription=a.onCreate.subscribe(e=>{this.assets.set(e.id,e)}),this.updateSubscription=a.onUpdate.subscribe(async t=>{if(this.assets.set(t.id,t),"material"==t.type)e.traverse(e=>{if(e instanceof i.Mesh)if(Array.isArray(e.material))for(let a=0;a<e.material.length;a++)this.refreshMaterial(e,e.material[a],t,a);else this.refreshMaterial(e,e.material,t)});else if("mesh"==t.type){this.findByAssetId(t.id).forEach(async e=>{this.remove(e.userData.src);const t=await this.materializeAndInitActor(e.userData.src);this.updated$.next({object:t,source:e.userData.src})});for(const e of this.assets.values())if("prefab"==e.type){if(!e.prefab.objects.some(e=>sa(e,e=>e.assetId==t.id,this.assets)))continue;this.findByAssetId(e.id).forEach(e=>{this.remove(e.userData.src),this.materializeAndInitActor(e.userData.src)})}this.landscapeManagers.forEach(e=>{const a=e.source?.grass?.layers?.some(e=>e.meshes.some(e=>e.assetId===t.id));a&&e.queueRefreshScatter(this.renderingView?.camera.position??new x,!0)})}else"prefab"===t.type?this.findByAssetId(t.id).forEach(e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}):"vfx"===t.type?this.dataProvider.getObjects().forEach(e=>{Vt(e,(e,a)=>{"vfx"===e.type&&e.assetId===t.id&&(this.remove(e),this.materializeAndInitActor(e))})}):"texture"===t.type&&this.scene.traverse(e=>{if(e instanceof m)if(Array.isArray(e.material))for(let a=0;a<e.material.length;a++)this.refreshMaterialTextures(e,e.material[a],t,a);else this.refreshMaterialTextures(e,e.material,t)})})}async refreshMaterialTextures(e,t,a,s){if("texture"!==a.type)return void console.error("Can not refresh material textures. Asset is not a texture",a);const r=await this.assetManagerService.getTexture(a);if(null!=r)if(t instanceof i.ShaderMaterial)for(const[e,s]of Object.entries(t.uniforms))s.value instanceof i.Texture&&s.value.userData.assetId===a.id&&(t.uniforms[e].value=r);else for(const[e,s]of Object.entries(t))s instanceof i.Texture&&s.userData.assetId===a.id&&(t[e]=r);else console.error("Can not refresh material textures. Texture not found",a)}async refreshMaterial(e,t,a,s){const r=t?.userData?.assetId;if(r!==a.id){const e=this.assets.get(r);let t=!1;if(null!=e)for(const s of Object.values(e.material.shaderParams)){if(s.type===Xe.Material&&s.value===a.id){t=!0;break}if(s.type===Xe.Array&&"element"in s&&s.element===Xe.Material&&s.value.includes(a.id)){t=!0;break}}if(!t)return}const i=await materialFromAsset(this.assets.get(r),this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1),n=i.userData;i.userData=t.userData,i.userData.hasBloom=n.hasBloom,i.userData.reflective=n.reflective,i.userData.outlineParameters=n.outlineParameters,null!=s?Wt(e.material[s],i)||(e.material[s]=i):Wt(e.material,i)||(e.material=i,e===this.sky&&this.applySkySettings(e.material))}getTopLevelActors(){return Array.from(this.materializedActors.entries()).filter(([e,t])=>!e.includes("/")).map(([,e])=>e)}get actorInstances(){return Array.from(this.materializedActors.values())}async initTextures(){const e=[];if(await Promise.all(this.dataProvider.getObjects().filter(e=>"shape_mesh"===e.type||"asset_mesh"===e.type).filter(e=>null!=e.materialAssignments).flatMap(e=>e.materialAssignments).map(async t=>{const a=this.assets.get(t.materialId);if(null!=a)for(const t of Object.values(a.material.shaderParams??{}))if(t.type===Xe.Texture&&"string"==typeof t.value){const a=this.assets.get(t.value),s=await this.assetManagerService.getTexture(a);null!=s&&e.push(s)}})),0!==e.length&&this.renderingView){console.log(`Initializing ${e.length} textures`),console.time("Init textures");for(const t of e)this.renderingView.renderer.initTexture(t);console.timeEnd("Init textures")}}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter(e=>null!=e.assetId&&"asset_mesh"==e.type).filter(e=>e.assetId)));await Promise.all(e.map(e=>this.assetsService.getAsset(e.assetId).then(e=>{if(null!=e)return this.assetManagerService.getMesh(e)}))),this.initTextures()}async init(){await this.preInit(),xt.clear(),It.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map(e=>this.materialize(e))),await this.initActorsPostInit()}async initVfx(){console.time("Init VFX");const e=new Set,t=[],a=new b;for(const s of this.actorInstances){const r=ta(s);for(const s of r){const r=s.asset;if(e.has(r.id))continue;e.add(r.id),r.vfx.emitters;const i=await s.create(a);a.add(i.object),a.add(i.particleSystemContainer),i.play(),i.onUpdate(.5),i.stop(),i.pause(),t.push(i)}}const s=this.renderingView.compileAsync(a);this.renderingView.initTextures(a),await s;for(const e of t)e.onEndPlay(),e.disposed.next(!0),e.object.removeFromParent();console.timeEnd("Init VFX")}async initActorsPostInit(e=Array.from(this.materializedActors.entries())){const t=e.map(async([e,t])=>{const a=t.object.userData.src??t.object.userData._src;if("vfx"===a.type)return Promise.resolve();const s=await this.assetsService.getAsset(a.assetId),r=e.split("/"),i=r.slice(0,-1),n=i.join("/"),o=(r[r.length-1],new Map);for(const[e,t]of this.materializedActors)if(o.set(e,t),0===n.length)e.includes("/")||o.set(e,t);else if(e.startsWith(n+"/")){const a=e.slice(n.length+1);a.includes("/")||o.set(a,t)}const l={...s?.actor?.params??{},...a.actor?.params??{}},c=[...a.actor?.innerParams??[]];for(let t=i.length-1;t>=0;t--){const a=i.slice(0,t+1).join("/"),s=this.idToSceneObject.get(a);if("prefab"===s?.type&&null!=s.prefab){const i=await this.assetsService.getAsset(s.assetId);if(null!=i){let n=!1,o=a+"/"+i.prefab?.mainActorId;for(;null!=o;){if(o===e){n=!0;break}o=this.prefabInstanceExposedActorMap.get(o)}if(n&&null!=s.prefab.params&&Object.assign(l,zt(s.prefab.params)),null!=s.prefab.innerParams)for(const e of s.prefab.innerParams){const a=r.slice(t+1);e.path.length>=a.length&&e.path.slice(0,a.length).every((e,t)=>e===a[t])&&c.push({path:e.path.slice(a.length),params:e.params})}}}}for(const e of c)await this.applyActorComponentParams(t,e.path.slice(),e.params,o);await this.attachEditorComponents(t,a,o);const h=await prepareClassParameters(l,t.constructor,this.assetsService,this.assetManagerService,o,this.renderingView,this.shaders,this.actorProvider,e=>{const t=n.length>0?n+"/"+e:e;return this.prefabInstanceExposedActorMap.get(t)??null});Object.assign(t,h);try{return await this.actorProvider.initActor(t)}catch(e){console.error(`Failed to initiate actor (name="${a.name}", id=${a.id})`,e)}});return Promise.all(t)}async attachEditorComponents(e,t,a){const s=t.actor?.components??[];for(const r of s){const s=this.componentTypes.find(e=>e.name===r.type);if(null==s){console.warn(`Component type '${r.type}' not found for actor ${t.id}`);continue}const i=e.attach(s.type);if(null!=r.params){const e=await prepareClassParameters(r.params,null,this.assetsService,this.assetManagerService,a,this.renderingView,this.shaders,this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);Object.assign(i,e)}for(const e of r.innerParams??[])await this.applyActorComponentParams(i,e.path.slice(),e.params,a)}}addVfxChildActors(e,t=e){}async applyActorComponentParams(e,t,a,s){const r=t.length,i=t.shift();if(0==r){const t=await prepareClassParameters(a,null,this.assetsService,this.assetManagerService,s,this.renderingView,this.shaders,this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[i]&&await this.applyActorComponentParams(e[i],t,a,s)}canObjectBeInstanced(e){return e.physics?.type!==ue.dynamic&&"sky"!==e.type&&"global_fog"!==e.type&&"world_env"!==e.type}async canAssetBeInstanced(e){let t=this._canBeInstancedCache.get(e.assetId);if(null==t){const a=await this.createFromAsset(e);if(null==a)return!1;const s=[];a.traverse(e=>{!Be(e)&&e.isMesh&&s.push(e)});const r=1==s.length&&0==s[0].children.length,i=!bt,n=s.every(e=>!Array.isArray(e.material)||1===e.material.length),o=s.some(e=>e instanceof m&&null!=e.geometry.morphAttributes&&Object.keys(e.geometry.morphAttributes).length>0),l=!0;t=s.length>0&&(r||n&&i)&&l&&!o,this._canBeInstancedCache.set(e.assetId,t)}return t}async preInit(){this.renderingView?.onLoop(()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)}),this.assetsService.getAssets().then(e=>{for(const t of e)this.assets.set(t.id,t)})}shouldBeMaterialized(e){if(!1===e.enabled)return!1;if(null!=this.detailTier&&"asset_mesh"===e.type&&null!=e.assetId){const t=this.assets.get(e.assetId);if(null!=t){const e=t.mesh?.detailTier;if(null!=e)return e<=this.detailTier}}return!0}async initWithInstancing(){await this.preInit(),await this.prefetchAssets(),xt.clear(),It.clear();const e=[],t=new je,a=new je,s=new je;let r=0,n=0,c=0;const h=new Map,p=new De(()=>new Map);for(const i of this.dataProvider.getObjects())await Vt(i,async(i,l,u)=>{if(!this.shouldBeMaterialized(i))return;const d="asset_mesh"==i.type&&this.canObjectBeInstanced(i)&&await this.canAssetBeInstanced(i),f="shape_mesh"===i.type&&"landscape"!==i.shape&&i.physics?.type!==ue.dynamic;if(d||f){if(l&&l.children?.length>0){const e=l.children.findIndex(e=>e.id===i.id);e>=0&&l.children.splice(e,1)}if(f){let e=i.shape+JSON.stringify(i.shapeParams??{})+i.castShadow+i.receiveShadow;const t=i.materialAssignments?.at(0)?.materialId,a=null!=t?this.assets.get(t):null;let r=null;if(!1&&null!=a&&"shader"!==a.material.type){if(e+=a.material.type+a.material.shader,null!=a.material.shaderParams){if(e+=Object.entries(a.material.shaderParams).filter(([e,t])=>"color"!=e).map(e=>JSON.stringify(e)).join(),null!=a.material.shaderParams.color){const e=a.material.shaderParams.color;e.type===Xe.Color&&null!=e.value&&(r=new o(e.value))}}e+=a.material.outlines,null!=a.material.outlineParams&&(e+=JSON.stringify(a.material.outlineParams)),e+=a.material.reflective,e+=a.material.bloom,e+=a.material.side,e+=a.material.side,e+=a.material.transparent,e+=a.material.alphaTest}else e+=t;s.push(e,{object:{...i,parentTransform:u},color:r}),c++}else{const e=this.assets.get(i.assetId);let s=h.get(i.assetId);if(null==s){const e=await this.createFromAsset(i,{assignMaterials:!1});if(null==e)return;if(s=h.get(i.assetId),null==s){s={useBatchedMesh:null!=Ve(e)&>(e,e=>!(e instanceof m)||this.testCanBatch(e.material,e.geometry)),assetMesh:e},h.set(i.assetId,s)}}const o=Nt(i.materialAssignments,e.materialAssignments);if(s.useBatchedMesh)await Oe(s.assetMesh,async e=>{if(!(e instanceof m))return;const t=Array.isArray(e.material)?e.material[0]:e.material,s=await this.resolveMaterialForAssignments(t,o);if(null!=s){p.get(i.id).set(e.uuid,s),aa(e.geometry,s);let t=Jt(s);t+=qt(e),a.push(t,{...i,parentTransform:u,meshUUID:e.uuid}),r++}else console.warn("Can not materialize mesh because missing material",i)});else{const e=i.assetId+JSON.stringify(i.materialAssignments??[]);t.push(e,{...i,parentTransform:u}),n++}}}else null==l&&e.push({...i,parentTransform:u})});console.log(`Scene init stats: \n Batched Assets: ${a.size} groups containing in total ${r} objects.\n Instanced Assets: ${t.size} groups containing in total ${n} objects.\n Shapes: ${s.size} batch groups containing in total ${c} objects. \n ${e.length} objects can not be batched. \n `);for(const e of h.values())this.prepareCollisionShapesForInstanced(e.assetMesh);console.time("materialize batches");for(const[e,t]of a.entries()){if(0==t.length)continue;let e;h.get(t[0].assetId).assetMesh;e=this.createBatchedMesh(t,p,h);const a=this.assets.get(t[0].assetId);e.castShadow=t[0].castShadow??a.castShadow??!0,e.receiveShadow=t[0].receiveShadow??a.receiveShadow??!0;const s=new ze;s.add(e),s.userData.src=t[0],s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}for(const e of t.values()){if(0==e.length)continue;let t;const a=h.get(e[0].assetId).assetMesh;t=await this.createInstancedMesh(e,a);const s=this.assets.get(e[0].assetId);t.castShadow=e[0].castShadow??s.castShadow??!0,t.receiveShadow=e[0].receiveShadow??s.receiveShadow??!0;const r=new ze;r.add(t),r.userData.src=e[0],a instanceof ze&&(r.collisionShapes=a.collisionShapes),this.prepareCollisionShapesForInstanced(r),r.castShadow=!1,r.receiveShadow=!1,this.scene.add(r)}console.timeEnd("materialize batches");for(const e of s.values()){if(0==e.length)continue;const t=e[0].object,a=await this.createFromShape(t),s=ke(a,e=>!Be(e)&&null!=e.geometry),r=s.material.clone();null!=e[0].color&&null!=r.color&&(r.color=new o(16777215));const n=s.geometry;let c,h;!(bt||r instanceof _||null==n.index)?(c=new i.BatchedMesh(e.length,n.getAttribute("position").count,n.index.count,r),c.perObjectFrustumCulled=!0,h=c.addGeometry(n)):c=new i.InstancedMesh(n,r,e.length),c.castShadow=a.castShadow??!0,c.receiveShadow=s.receiveShadow??!0;for(let t=0;t<e.length;t++){const a=e[t],s=(new i.Matrix4).compose((new x).fromArray(a.object.position),(new v).setFromEuler((new l).fromArray(a.object.rotation)),(new x).fromArray(a.object.scale)),r=(new d).copy(a.object.parentTransform).multiply(s);let n;n=c instanceof i.BatchedMesh?c.addInstance(h):t,c.setMatrixAt(n,r),a.color}for(let t=0;t<e.length;t++){const s=e[t],r=new ze;r.userData.src=e[0],a instanceof Ue&&(r.collisionShapes=[a.collisionShape]),r.castShadow=!1,r.receiveShadow=!1,this.scene.add(r),r.add(c),null==c.userData.hasCollision&&(c.userData.hasCollision=[]),c.userData.hasCollision[t]=!!s.object.collisionDetection}}await Promise.all(e.map(e=>this.materialize(e))),await this.initActorsPostInit(),await this.initVfx()}prepareCollisionShapesForInstanced(e){e instanceof ze&&e.collisionShapes.forEach(e=>{e instanceof a&&e.mesh instanceof m&&(e.mesh=e.mesh.geometry)})}testCanBatch(e,t){return!bt&&(!Array.isArray(e)||1==e.length)&&this.testCanBatchMaterial(e)}testCanBatchMaterial(e){const t=Array.isArray(e)?e[0]:e;return null!=t&&(!(t instanceof y)||null==t.bumpMap&&null==t.lightMap&&null==t.displacementMap)}createBatchedMesh(e,t,a){const s=new je;for(const t of e)null!=t.meshUUID?s.push(t.meshUUID??t.assetId,t):console.warn("Missing mesh uuid for batching");let r=0,n=0,l=0;const c=new Map;for(const[e,t]of s.entries()){const s=t[0].assetId,i=a.get(s);if(null==i){console.warn("Missing batching info for asset id "+s);continue}const o=ke(i.assetMesh,t=>t instanceof m&&t.uuid===e);if(null==o){console.warn("Missing mesh in batched asset");continue}c.set(e,o);const h=o.geometry.getAttribute("position");null==h&&console.warn("Missing position attribute for batched mesh"),r+=o.geometry.index.count*t.length,n+=h.count*t.length,l+=t.length}const h=["color","map","roughness","roughnessMap","metalness","metalnessMap","opacity","alphaMap","aoMap","aoMapIntensity","normalMap","normalScale","emissive","emissiveIntensity","emissiveMap"];let p=new Map;const u=[];let d=new i.MeshStandardMaterial({color:"white"});const f=t.get(e[0].id).get(e[0].meshUUID);if(null==f)throw"missing source material";if(f instanceof y&&!(f instanceof i.MeshPhysicalMaterial)){const a=new Set,s=new Map;for(const r of e){const e=t.get(r.id).get(r.meshUUID);if(null==e)throw"missing mat";for(const t of h){let r=e[t];r instanceof i.CompressedArrayTexture&&null!=r.userData.index&&(r=r.userData.index);const n=s.get(t);void 0===n||ea(r,n)?s.set(t,r):a.add(t)}}for(const e of a){let t;const a=f[e];if("number"==typeof a){let a=u.find(e=>e.params.length<4);if(null==a){const t="vp"+u.length;a={name:t,params:[e],node:T(t)},u.push(a)}else a.params.push(e);t=Kt(a.node,a.params.length-1)}else if(a instanceof I)t=T(e);else if(a instanceof x||a instanceof o)t=C(e);else if(a instanceof S)t=P(e);else if(a instanceof i.CompressedArrayTexture)t=D(e+"_i");else if(a instanceof A)continue;p.set(e,t)}let r=Y.uv;f instanceof mt&&null!=f.heightMap&&(r=ft(r,G(f.heightMap),z(f.heightScale)));let n=Ht(p.get("opacity"),F)??z(f.opacity??1);if(null!=f.alphaMap){let e;if(f.alphaMap instanceof i.CompressedArrayTexture){const t=J(f.alphaMap),a=Ht(p.get("alphaMap"),F)??z(f.alphaMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.alphaMap).sample(r);n=n.multiply(e.r)}let l=$(Ht(p.get("color"),te)??f.color,n);if(null!=f.map){let e;if(f.map instanceof i.CompressedArrayTexture){const t=J(f.map),a=Ht(p.get("map"),F)??z(f.map.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.map).sample(r);l=l.multiply(e),n=n.multiply(e.a)}f.vertexColors&&(l=l.multiply(ae(X(j.color.rgb),1)));let c=$(Ht(p.get("emissive"),te)??f.emissive,n);if(null!=f.emissiveMap){let e;if(f.emissiveMap instanceof i.CompressedArrayTexture){const t=J(f.emissiveMap),a=Ht(p.get("emissiveMap"),F)??z(f.emissiveMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.emissiveMap).sample(r);c=c.multiply(e)}const m=Ht(p.get("emissiveIntensity"),F)??z(f.emissiveIntensity??1),g=Ht(p.get("normalScale"),Q)??K(f.normalScale??new S(1,1));let y=Z.normal;if(null!=f.normalMap){let e;if(f.normalMap instanceof i.CompressedArrayTexture){const t=J(f.normalMap),a=Ht(p.get("normalMap"),F)??z(f.normalMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.normalMap).sample(r);y=O(e.rgb,g.x)}let w=Ht(p.get("roughness"),F)??z(f.roughness??1);if(null!=f.roughnessMap){let e;if(f.roughnessMap instanceof i.CompressedArrayTexture){const t=J(f.roughnessMap),a=Ht(p.get("roughnessMap"),F)??z(f.roughnessMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.roughnessMap).sample(r);w=w.multiply(e.g)}let M=Ht(p.get("metalness"),F)??z(f.metalness??0);if(null!=f.metalnessMap){let e;if(f.metalnessMap instanceof i.CompressedArrayTexture){const t=J(f.metalnessMap),a=Ht(p.get("metalnessMap"),F)??z(f.metalnessMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.metalnessMap).sample(r);M=M.multiply(e.b)}let v=z(1);if(null!=f.aoMap){let e;if(f.aoMap instanceof i.CompressedArrayTexture){const t=J(f.aoMap),a=Ht(p.get("aoMap"),F)??z(f.aoMap.userData.index??0);e=t.sample(ee(r.x,r.y,a))}else e=G(f.aoMap).sample(r);v=v.multiply(e.r)}const b=Ht(p.get("aoMapIntensity"),F)??z(f.aoMapIntensity??0);let E=y;!0!==f.userData.disableAO&&(E=N("DOUBLE_SIDED",E,e=>L(new V("gl_FrontFacing"),e,e.multiplyScalar(-1))));const k=new _({color:R({color:l,roughness:w,metalness:M,ambientOcclusion:v,ambientOcclusionIntensity:b,emissive:c,emissiveIntensity:m,normal:E}),normal:y,roughness:w,emissive:c.rgb,transparent:f.transparent,alphaTest:f.alphaTest,envMap:f.envMap,opacity:n});null!=f.envMap&&(k.uniforms.envMapIntensity={value:f.envMapIntensity},k.uniforms.envMapRotation={value:Zt(f.envMapRotation,f.envMap)}),k.envMap=f.envMap,k.side=f.side,d=k}else{d=f;for(const a of e){const e=t.get(a.id).get(a.meshUUID);if(e!=d){console.error(`Different materials in group for object ${a.id} and mesh uuid ${a.meshUUID}`,{objectMaterial:e,sourceMaterial:f});break}}}const g=new dt(l,n,r,d);for(const e of u)g.initUniform(e.name,4);for(const[e,t]of p.entries()){if(u.some(t=>t.params.includes(e)))continue;let a=1;t instanceof se||t instanceof te?a=4:t instanceof Q&&(a=2),g.initUniform(e,a,0)}for(const[e,r]of s.entries()){const s=r[0].assetId,n=c.get(e);if(null==n){console.error(`Missing single asset mesh for mesh uuid ${e} and asset id ${s}`);continue}if(null==n.geometry){console.error("Missing geometry on mesh mesh");continue}const l=g.addGeometry(n.geometry),h=a.get(s);if(null==h){console.warn("Missing batching info when configuring for asset id "+s);continue}const d=Ve(h.assetMesh)?.uuid===e,m=h.assetMesh instanceof ze&&d?h.assetMesh.collisionShapes:void 0,f=this.configureBatchedInstancedMesh(r,g,n,l,m);for(let e=0;e<f.length;e++){const a=r[e],s=f[e],n=t.get(a.id).get(a.meshUUID);for(const e of u){let t=Qt.set(0,0,0,0);for(let a=0;a<e.params.length;a++){const s=n[e.params[a]];"number"==typeof s&&t.setComponent(a,s)}g.setUniformAt(e.name,s,t)}for(let e of p.keys()){if(u.some(t=>t.params.includes(e)))continue;let t=n[e];if(t instanceof o&&(t=new x(t.r,t.g,t.b)),t instanceof i.CompressedArrayTexture)t=t.userData.index??0,e+="_i";else if(t instanceof A||null==t)continue;g.setUniformAt(e,s,t)}}}return g}async createInstancedMesh(e,t){const a=ke(t,e=>!Be(e)&&null!=e.geometry),s=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(t,Nt(e[0].materialAssignments,s.materialAssignments)),a.updateMatrix();const r=a.geometry.clone(),n=a.material;let o;if(o=new i.InstancedMesh(r,n,e.length),this.configureBatchedInstancedMesh(e,o,a),a.material instanceof u&&o.castShadow&&o.receiveShadow&&Array.isArray(n))for(const e of n);return o}configureBatchedInstancedMesh(e,t,a,s,r){const n=[];a.updateWorldMatrix(!0,!0);for(let o=0;o<e.length;o++){let c=o;t instanceof i.BatchedMesh&&(c=t.addInstance(s)),n.push(c);const h=(new i.Matrix4).compose((new x).fromArray(e[o].position),(new v).setFromEuler((new l).fromArray(e[o].rotation)),(new x).fromArray(e[o].scale)),p=(new d).copy(e[o].parentTransform).multiply(h).multiply(a.matrixWorld);t.setMatrixAt(c,p),null==t.userData.hasCollision&&(t.userData.hasCollision=[]),t.userData.hasCollision[c]=!!e[o].collisionDetection,null!=r&&(null==t.userData.collisionShapes&&(t.userData.collisionShapes=[]),t.userData.collisionShapes[c]=r)}return n}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("world_env"===e.type)this.resetWorldEnv(),this.worldEnvObj=null;else if("actor"==e.type||"vfx"===e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay()):console.warn("Failed to remove actor",e)}else"prefab"===e.type&&this.materializedActors.forEach((t,a)=>{a.startsWith(e.id)&&(t.disposed.next(!0),t.onEndPlay()),this.materializedActors.delete(a)});const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter(t=>t.object.userData.src?.id===e.id).forEach(e=>this.components.splice(this.components.indexOf(e,1))),this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))}),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex(t=>t.source.id===e.id);if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return Ee(this.scene,t=>t.userData.src?.assetId==e,e=>null!=e.userData.src)}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter(e=>"null"!==e.materialId).map(t=>this.applyMaterial(e,t)))}async applyMaterial(e,t){await applyMaterial(e,t,e=>{const t=this.assets.get(e);if(null!=t)try{return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}catch(e){console.error("Failed to apply material",e)}},this._originalMaterials)}async resolveMaterialForAssignments(e,t){let a=e,s=null,r=null;for(const e of t??[]){if(!$t(a,e,s,r))continue;const t=this.assets.get(e.materialId);if(null==t){console.warn("Missing material with id "+e.materialId);continue}const i=await materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!0);null!=i&&a.id!==i.id&&(s=s??Ut(a),r=r??a.name,a=i)}return a}unapplyMaterials(e){e.traverse(async e=>{if(e instanceof m)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material})}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(he));Ee(this.scene,e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type)).forEach(async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)})}updateComponents(e){this.componentTypes=e,Ee(this.scene,e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&(e.userData.src.actor?.components?.length??0)>0).forEach(async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)})}updateShaders(e){this.shaders=e;for(const[e,t]of xt.entries())t.userData.customShaderName&&xt.delete(e);this.landscapeManagers.forEach(t=>t.updateShaders(e)),Ee(this.scene,e=>!0).forEach(e=>{e.traverse(async e=>{if(e instanceof m)if(Array.isArray(e.material))for(let t=0;t<e.material.length;t++){const a=e.material[t].userData?.customShaderName;if(null!=a){const a=this.assets.get(e.material[t].userData.assetId);this.refreshMaterial(e,e.material[t],a,t)}}else{const t=e.material.userData?.customShaderName;if(null!=t){const t=this.assets.get(e.material.userData.assetId);this.refreshMaterial(e,e.material,t)}}})})}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);if("world_env"===e.type&&null!=this.worldEnvObj)return void this.updateWorldEnv(e);const t=this.sceneObjectMap.get(e.id);if(t){let s=!1;if(t.traverseAncestors(e=>{"_hology_transform_group"===e.name&&(s=!0)}),!s){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse(e=>{e instanceof m&&(e.material.wireframe=!0)}):t.traverse(e=>{e instanceof m&&(e.material.wireframe=!1)})}if("asset_mesh"===e.type&&t.userData.assetId!==e.assetId){this.remove(e);const t=await this.materializeAndInitActor(e);return void this.updated$.next({object:t,source:e})}if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);Nt(e.materialAssignments,a.materialAssignments).forEach(e=>this.applyMaterial(t,e))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(s||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type){if("point"==e.light.type){const a=t;a.color=new o(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0),a.userData.volumetricIntensity=e.light.point.volumetricIntensity}else if("spot"==e.light.type){const a=t;a.color=new o(e.light.spot.color),a.intensity=e.light.spot.intensity,a.decay=e.light.spot.decay,a.angle=e.light.spot.angle,a.penumbra=e.light.spot.penumbra,a.castShadow=e.light.spot.castShadow,a.distance=Math.max(e.light.spot.distance,0),a.userData.volumetricIntensity=e.light.spot.volumetricIntensity}else if("directional"===e.light.type)this.applyDirectionalLight(e.light.directional,e);else if("ambient"===e.light.type)this.applyDirectionalAmbientLight(t,e.light.ambient,e);else if("rectArea"===e.light.type){const a=t;a.color=new o(e.light.rectArea.color),a.intensity=e.light.rectArea.intensity,null!=e.scale&&(a.width=e.scale[0],a.height=e.scale[1]),a.children.forEach(e=>{e instanceof yt&&e.update()})}}else if("landscape"===e.shape){const a=this.landscapeManagers.find(t=>t.source.id===e.id).source.landscape.options.density!==e.landscape.options.density;if(this.inEditor&&a){this.remove(e);const t=await this.materializeAndInitActor(e);return void this.updated$.next({object:t,source:e})}this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(t=>{t.updateSource(e),t.queueRefreshScatter(this.renderingView.camera.position,!0,e=>!0)})}else if("global_fog"===e.type){const t=(this.scene.fog instanceof h?"density":"linear")!==e.fog.type;this.scene.fog=Et(e.fog),t&&(a=this.scene).traverse(e=>{if(e instanceof m){const t=e.material;t instanceof _&&(a.fog instanceof c?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof h&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}}),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.materializedActors.get(e.id);if(t instanceof ht){const a=await prepareClassParameters(e.actor.params,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,[],this.actorProvider,e=>this.prefabInstanceExposedActorMap.get(e)??null);return void Object.assign(t,a)}const a=this.editorActorParamSnapshot.get(e.id);null!=a&&a===JSON.stringify(e.actor)||s||(this.remove(e),await this.materializeAndInitActor(e))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof Ue&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}if("shape_mesh"===e.type&&"landscape"!==e.shape)St(t,e.castShadow,e.receiveShadow);else if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);if(null==a)return void console.error("Asset not found",e.assetId);const s=e.receiveShadow??!!a.receiveShadow,r=e.castShadow??!!a.castShadow;St(t,r,s)}e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a;this.renderingView.renderer.shadowMap.needsUpdate=!0}async materializeAndInitActor(e,t=this.findParent(e)){const a=await this.materialize(e,t),s=Array.from(this.materializedActors.entries()).filter(([t])=>t===e.id||t.startsWith(e.id+"/"));return await this.initActorsPostInit(s),a}findParent(e){const t=this.dataProvider.getObjects().flatMap(t=>t.id===e.id?null:Te(t,t=>t.children?.some(t=>t.id===e.id),()=>!0))[0];return null==t?this.scene:null!=t?Ee(this.scene,e=>e.userData?.src?.id===t.id,e=>null!=e.userData?.src)[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new o(this.scene.fog.color))}findMeshWithGeometry(e){let t;return e.traverse(e=>{e instanceof m&&e.geometry&&(t=e)}),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;let a=1;for(const t of e.vertexMaterials)a=Math.max(t.w.length,a);const s=Pe(e.vertexMaterials,e=>e.m);t.traverse(e=>{if(e instanceof m){if(null==e.geometry)return;if(Lt(Je(e,0,!1)),a>0){Lt(Je(e,0,!1))}}});const r=new Set;for(const[e,i]of s.entries()){const s=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let n=!1;if(null==s||null==s.geometry)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const o=Je(s,0,!0);Lt(o);for(const e of i)o.setX(e.i,e.w[0]??0),o.setY(e.i,e.w[1]??0),o.setZ(e.i,e.w[2]??0),o.setW(e.i,e.w[3]??0),n=!0;if(a>0){const e=Je(s,4,!0);Lt(e);for(const t of i)e.setX(t.i,t.w[4]??0),e.setY(t.i,t.w[5]??0),e.setZ(t.i,t.w[6]??0),e.setW(t.i,t.w[7]??0),e.needsUpdate=!0,n=!0}n&&r.add(e)}this.inEditor&&this.landscapeManagers.filter(t=>t.source.id===e.id).forEach(e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,e=>r.has(e.name)))}async materialize(e,t,a=!1,s){const r=this.getNestedActorId(e.id,s);if(this.idToSceneObject.set(r,e),!this.shouldBeMaterialized(e))return;let i,n;switch(e.type){case"asset_mesh":i=await this.createFromAsset(e);break;case"shape_mesh":i=await this.createFromShape(e);break;case"light":i=await this.createLight(e);break;case"particles":i=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Et(e.fog),this.fixFogColor(),i=new p;break;case"sky":this.sky=Qe(),this.updateSky(e),i=this.sky;break;case"world_env":this.updateWorldEnv(e),i=new p,this.worldEnvObj=i;break;case"actor":({object:i,actor:n}=await this.createFromActor(e,s));break;case"group":i=new p;break;case"prefab":i=await this.createFromPrefab(e,s,t);break;case"vfx":i=await this.createFromVfx(e,s);break;default:console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version or because of an error in the scene data. Scene object: id=${e.id}, name=${e.name}`)}if(null!=i){if(e.name&&e.name.length>0&&(i.name=e.name),this.applyTransform(e,i),a?i.userData._src=e:i.userData.src=e,null!=n&&(i.userData.actor=n),this.inEditor,this.inEditor,this.objectMap.set(i.uuid,e),this.sceneObjectMap.set(e.id,i),e.physics?.type!==ue.dynamic||null==t||this.inEditor?null==t?this.scene.add(i):null==t||"actor"!==e.type||this.inEditor?t?.add(i):(t.add(i),this.scene?.attach(i),console.log(i)):(t.add(i),i.getWorldPosition(i.position),i.getWorldQuaternion(i.quaternion),i.getWorldScale(i.scale),this.scene?.attach(i)),null!=e.children&&await Promise.all(e.children?.map(e=>this.materialize(e,i,a))),this.inEditor||null!=t||"asset_mesh"!=e.type&&"shape_mesh"!==e.type&&"prefab"!==e.type&&"group"!==e.type||"landscape"===e.shape||null!=e.physics?.type&&e.physics.type==ue.dynamic||Tt(i),null!=this.renderingView)return this.renderingView.renderer.shadowMap.needsUpdate=!0,i;console.warn("RenderingView not found in materializer")}}applyTransform(e,t){null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)}updateWorldEnv(e){this.renderingView.aoPass.enabled=e.worldEnv.ao.enabled,this.renderingView.aoPass.blendIntensity=e.worldEnv.ao.blendIntensity,this.renderingView.aoPass.updateGtaoMaterial(e.worldEnv.ao);const t=e.worldEnv.toneMapping;null!=t&&(this.renderingView.baseToneMapping=t.mapping??0,this.renderingView.baseToneMappingExposure=t.exposure??1,this.renderingView.renderer.toneMapping=this.renderingView.baseToneMapping,this.renderingView.renderer.toneMappingExposure=this.renderingView.baseToneMappingExposure);const a=e.worldEnv.environment;null!=a&&null!=a.textureId?this.assetManagerService.getTexture(this.assets.get(a.textureId)).then(e=>{null==this.pmremGenerator&&(this.pmremGenerator=new i.PMREMGenerator(this.renderingView.renderer),this.pmremGenerator.compileEquirectangularShader()),this.pmremGeneratorResults.has(e)||this.pmremGeneratorResults.set(e,this.pmremGenerator.fromEquirectangular(e).texture);const t=this.pmremGeneratorResults.get(e);this.renderingView.scene.environment=t,this.renderingView.scene.environmentIntensity=a.intensity??1}):this.renderingView.scene.environment=null}resetWorldEnv(){this.renderingView.aoPass.enabled=!1,this.renderingView.aoPass.blendIntensity=1,this.renderingView.aoPass.output=0,this.renderingView.baseToneMapping=0,this.renderingView.baseToneMappingExposure=1,this.renderingView.renderer.toneMapping=this.renderingView.baseToneMapping,this.renderingView.renderer.toneMappingExposure=this.renderingView.baseToneMappingExposure}async updateSky(e){null!=this.sky&&(null==e?.sky?.materialId&&this.sky.material!==et?(this.sky.material=et,this.applySkySettings(this.sky.material)):this.sky.material.userData?.assetId!==e.sky.materialId&&this.updateSkyMaterial(e),null!=e.rotation&&this.sky.rotation.fromArray(e.rotation))}async updateSkyMaterial(e){const t=await this.assetsService.getAsset(e.sky.materialId);if(null==t)return void console.warn(`No material asset found for sky with id ${e.sky.materialId}`);const a=await materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);this.applySkySettings(a),null!=this.sky?this.sky.material=a:console.warn("No sky has been created")}applySkySettings(e){e.side=i.BackSide,(e instanceof y||e instanceof i.MeshBasicMaterial||e instanceof i.ShaderMaterial)&&(e.fog=!1),e.depthTest=!1}async createComponent(e,t,a,s){const r=new Mt[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e,t){const a=this.actorTypes.find(t=>t.name===e.actor?.type)?.type??he[e.actor?.type];if(null==a)return{object:null,actor:null};this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const s=await this.actorProvider.create(a,(new x).fromArray(e.position),(new l).fromArray(e.rotation),!0);return this.materializedActors.set(this.getNestedActorId(e.id,t),s),{object:s?.object,actor:s}}getNestedActorId(e,t){return null!=t?t.sceneObjectChain.join("/")+"/"+e:e}async createFromVfx(e,t){const a=await this.assetsService.getAsset(e.assetId);null==a&&console.error("Could not find asset",e);const s=await this.actorProvider.create(ie,(new x).fromArray(e.position),(new l).fromArray(e.rotation),!1);try{await s.fromAsset(a)}catch(e){return console.error("Failed to create VFX asset",e),null}return s.play(),this.materializedActors.set(this.getNestedActorId(e.id,t),s),null!=s&&(s.object.userData.actor=s),s?.object}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e),a.traverse(e=>{e instanceof m&&this._originalMaterials.set(e.id,e.material)});else{let s=new y({name:"Default",color:new o("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});!0===e.collider&&(s.opacity=.3,s.color.set(2517460),s.transparent=!0);const r=await this.createMeshByShape(e.shape,s,e.shapeParams);r.castShadow=e.castShadow??!0,r.receiveShadow=e.castShadow??!1,e.collisionDetection||(r.collisionShape=null),r.physics=e.physics,a=r,this._originalMaterials.set(a.id,r.material),a.traverse(e=>{})}return t||(await Promise.all((e.materialAssignments??[]).filter(e=>null!=e.materialId).map(e=>this.applyMaterial(a,e))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new p;const a=We(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new $e(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,t=>{(e.materialAssignments??[]).filter(e=>null!=e.materialId).forEach(e=>this.applyMaterial(t,e))});return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new Le(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach(e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()}),this.inEditor&&!a||setTimeout(()=>Re(r),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&Ze.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);if(!this.geometryCache.has(r)){const t=Ye[e].geometry(s);(function(e){return null!=e.index&&e.hasAttribute("position")&&e.hasAttribute("normal")&&e.hasAttribute("uv")})(t)&&t.computeTangents(),this.geometryCache.set(r,t)}this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,Ye[e].collision(s));return new Ue(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e,t){const a=this.assets.get(e.assetId)??await this.assetsService.getAsset(e.assetId);if(null==a)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:s}=await this.assetManagerService.getMesh(a,{mergeGeomtries:!0});if(!1!==t?.assignMaterials)try{await Promise.all(Nt(e.materialAssignments,a.materialAssignments).map(e=>this.applyMaterial(s,e)))}catch(t){console.error("Failed to apply material"+t,e)}const r=e.receiveShadow??!!a.receiveShadow,i=e.castShadow??!!a.castShadow;return s.receiveShadow=r,St(s,i,r),e.collisionDetection||(s.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(s.physics=e.physics),this.applyVertexMaterials(e,s),s.traverse(e=>{e instanceof m&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&e.geometry.computeBoundsTree()}),s.userData.assetId=e.assetId,s}async createFromPrefab(e,t,a){const s=await this.assetsService.getAsset(e.assetId);if(null==s)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);null==t&&(t={sceneObjectChain:[]}),t.sceneObjectChain.push(e.id);const{object:r}=await this.createFromPrefabAsset(s,t,a,e);return t.sceneObjectChain.pop(),r}async createFromPrefabAsset(e,t,a,s,r=!0){const i=new p;null!=s&&this.applyTransform(s,i),null!=a&&a.add(i),await Promise.all(e.prefab.objects.filter(e=>"global_fog"!==e.type&&"world_env"!==e.type).map(e=>this.materialize(e,i,!0,structuredClone(t))));const n=t.sceneObjectChain.join("/"),o=Array.from(this.materializedActors.entries()).filter(([e,a])=>e.startsWith(n)&&e.split("/").length-1===t.sceneObjectChain.length);let l;if(o.forEach(e=>{}),null!=e.prefab?.mainActorId){const a=t.sceneObjectChain.join("/")+"/"+e.prefab.mainActorId;l=this.materializedActors.get(a)}r||await this.initActorsPostInit(o);const c=Array.from(this.materializedActors.entries()).filter(([e,t])=>e.startsWith(n)).map(([,e])=>e);if(null!=e.prefab?.mainActorId&&null!=s){const a=t.sceneObjectChain.join("/"),s=a+"/"+e.prefab.mainActorId;this.prefabInstanceExposedActorMap.set(a,s)}return{object:i,actors:c,mainActor:l}}async createParticleSystem(e){await this.assetsService.getAsset(e.assetId);return new w}async createLight(e){if("point"===e.light.type){const t=new M(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s)}return t}if("spot"===e.light.type){const t=new i.SpotLight(e.light.spot.color,e.light.spot.intensity,e.light.spot.distance,e.light.spot.angle,e.light.spot.penumbra,e.light.spot.decay);if(t.castShadow=e.light.spot.castShadow??!0,t.target=new w,t.target.position.set(0,-1,0),t.add(t.target),this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s),t.add(new i.SpotLightHelper(t))}return t}if("rectArea"===e.light.type){const t=new i.RectAreaLight(e.light.rectArea.color,e.light.rectArea.intensity,e.scale?e.scale[0]:1,e.scale?e.scale[1]:1);if(this.inEditor){const e=(new i.TextureLoader).load("assets/light-bulb-icon.webp"),a=new i.SpriteMaterial({map:e,alphaTest:.5}),s=new pt(a);s.scale.multiplyScalar(.6),t.add(s);const r=new yt(t);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional,e),new p):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient,e),new p):void 0}applyDirectionalAmbientLight(e,t,a){const s=this.scene.children.find(e=>e.name===Ke);null!=s?(s.intensity=t.intensity,s.color.set(t.color),s.groundColor.set(t.color),s.userData.src=a,s.userData.volumetricIntensity=t.volumetricIntensity):console.warn("Couldn't find ambient light")}applyDirectionalLight(e,t){for(const a of this.renderingView.csm.lights)a.intensity=e.intensity,a.color.set(e.color),a.castShadow=e.castShadow,a.userData.src=t,a.userData.volumetricIntensity=e.volumetricIntensity;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.createAssetSubscription.unsubscribe(),this.materializedActors.forEach(e=>e.disposed.next(!0)),this.materializedActors.clear()}};At=e([re(),t("design:paramtypes",[b,Object,Ne,Fe,fe,Array,Array,Object,Array])],At);export{At as SceneMaterializer};function St(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse(e=>{e.castShadow=t,e.receiveShadow=a})}const xt=new Map,It=new Map,jt=new f({color:16711935}),Dt=new Map;export async function materialFromAsset(e,t,a,s,r,i=!0){const n=JSON.stringify(e.material)+t?._id;return i&&xt.has(n)?xt.get(n):i&&It.has(n)?await It.get(n):It.set(n,_materialFromAsset(n,e,t,a,s,r,i)).get(n)}export async function _materialFromAsset(e,t,a,r,n,l,c=!0){const h={opacity:t.material.params?.opacity??1,map:null,emissive:t.material.params?.emissive??null,metalness:t.material.params?.metalness??0,flatShading:t.material.params?.flatShading??!1,color:new o(t.material.params?.color),transparent:null!=t.material.params?.opacity&&t.material.params?.opacity<1},p={};if(null!=t.material.params?.map){const e=t.material.params.map,a=await r.getAsset(e);null!=a&&(h.map=await n.getTexture(a))}let u;switch(t.material.type){case"phong":u=new g({...h,...p});break;case"water":u=He(h,a);break;case"grassFoliage":u=qe({color:h.color,map:h.map},a);break;case"grass":u=Ge({...h,colorTwo:new o(t.material.params.colorTwo),colorThree:new o(t.material.params.colorThree)},a);break;case"standard":case"unlit":case"toon":case"layered":case"lambert":case"shader":case"landscape":case"landscape-composite":case"decal-unlit":case"decal-standard":case"sprite":const e={standard:vt?ve:Se,lambert:ve,unlit:xe,toon:ut,layered:lt,landscape:Ae,"landscape-composite":be,"decal-unlit":at,"decal-standard":st,sprite:s}[t.material.type]??l.find(e=>e.name==t.material.shader)?.type;if(e){try{let s=new e;const i=await prepareClassParameters(t.material?.shaderParams??{},e,r,n,null,a,l);Object.assign(s,i),u=s.build()}catch(e){console.log("Shader runtime error: "+e,e),Dt.has(t.material.shader)||Dt.set(t.material.shader,jt.clone()),u=Dt.get(t.material.shader)}u.userData.customShaderName=t.material.shader}else console.warn("Missing shader implementation with name "+t.material.shader),u=jt;break;default:throw new Error("Unsupported material type "+t.material.type)}return a?.csm.setupMaterial(u),null!=a&&xt.set(e,u),u.side=t.material.side??u.side??i.FrontSide,u.transparent=(t.material.transparent??h.transparent??!1)||u.transparent,u.alphaTest=t.material.alphaTest??u.alphaTest??0,null!=t.material.blending&&(u.blending=de[t.material.blending]??i.NormalBlending),t.material.bloom&&(u.userData.hasBloom=!0),t.material.reflective&&(u.userData.reflective=!0),!0===t.material.outlines&&(u.userData.outlineParameters={},null!=t.material.outlineParams&&(null!=t.material.outlineParams.color&&(u.userData.outlineParameters.color=new o(t.material.outlineParams.color).toArray()),null!=t.material.outlineParams.thickness&&(u.userData.outlineParameters.thickness=t.material.outlineParams.thickness))),u.userData.assetId=t.id,It.delete(e),u}export async function prepareClassParameters(e,t,a,s,r,i,n,o,l){const c={};for(const[t,h]of Object.entries(e)){if(!1===h.override)continue;const e=await Ct(t,h,a,s,r,i,n,o,void 0,void 0,l);null!=e&&(c[t]=e)}return c}export async function prepareShapeParameters(e,t,a){const s={};for(const[r,i]of Object.entries(e)){const e=await Ct(r,i,t,a,null,void 0,void 0,void 0,void 0,void 0);null!=e&&(s[r]=e)}return s}const Pt=new Map;async function Ct(e,t,a,s,r,i,n,c,h=t.value,p=t.type,u){if(null==t||null==h||""===h)return null;switch(p){case Xe.Array:if(Array.isArray(h)&&"element"in t)return await Promise.all(h.map(o=>Ct(e,t,a,s,r,i,n,c,o,t.element,u)));break;case Xe.Number:case Xe.FloatNode:let p;if("string"==typeof h?p=parseFloat(h):"number"==typeof h&&(p=h),t.type===Xe.FloatNode){if("object"==typeof h&&"a"in h&&"b"in h){const e=h;if(null==e.a)return null;const t="string"==typeof e.a?parseFloat(e.a):e.a;if(null==e.b)return t;const a="string"==typeof e.b?parseFloat(e.b):e.b,s=function(e){let t=Pt.get(e);return null==t&&(t=ge(tt.decode(e)),Pt.set(e,t)),t}(e.easing),r=s.sample(ye(we.energy));return B(z(t),z(a),r)}return z(p)}return p;case Xe.Texture:let d=await s.getTexture(await a.getAsset(h));return"envmap"===e.toLowerCase()&&null!=i&&(d=i.getEnvTexture(d)),d;case Xe.Sampler2DNode:const m=await a.getAsset(h);if(null!=m.texture?.textureArrayFileKey){const{texture:e,layerIndex:t}=await s.getTextureArray(m);if(e&&null!=t)return new H(null,e,z(t))}const f=await s.getTexture(m);return f?G(f):null;case Xe.Boolean:return h;case Xe.BooleanNode:return E(h);case Xe.Vector2:case Xe.Vec2Node:if("object"==typeof h){const e=h instanceof Array?(new S).fromArray(h):new S(h.x,h.y);return t.type===Xe.Vec2Node?K(e):e}return null;case Xe.Vector3:case Xe.Vec3Node:if("object"==typeof h){const e=h instanceof Array?(new x).fromArray(h):new x(h.x,h.y,h.z);return t.type===Xe.Vec3Node?ee(e):e}return null;case Xe.Color:case Xe.RgbNode:const g=new o(h);return t.type===Xe.RgbNode?U(g):g;case Xe.String:return h;case Xe.BaseActor:const y=h;if(null==r&&console.warn("Class parameters can not be prepared as actors are not passed in"),null==y)return null;if("object"==typeof y&&null!=y.type&&null!=y.id){if("actor"===y.type)return r?.get(y.id)??null;if("prefab"===y.type){const e=u?u(y.id):null;if(null!=e)return r?.get(e)??null;const t=[];for(const[e,a]of r?.entries()??[])e.startsWith(y.id+"/")&&t.push(a);return 1===t.length?t[0]:null}}if("string"==typeof y){const e=r?.get(y);if(null!=e)return e;const t=u?u(y):null;if(null!=t)return r?.get(t)??null;const a=[];for(const[e,t]of r?.entries()??[])e.startsWith(y+"/")&&a.push(t);return 1===a.length?a[0]:null}return null;case Xe.Euler:const w=h;return(new l).fromArray(w);case Xe.Object3D:{const e=await a.getAsset(h);return(await s.getMesh(e,{applyMaterials:!0})).scene}case Xe.Material:{if(null==h)return null;const e=await a.getAsset(h);return null==e?(console.warn("Material asset not found for material parameter",h),null):null==e.material?(console.warn("Using a non-material asset for material parameter"),null):await materialFromAsset(e,i,a,s,n)}case Xe.AudioBuffer:return await s.getAudio(await a.getAsset(h));case Xe.VisualEffect:const M=await a.getAsset(h);if(null==c){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in M)return new ne(c,M);console.error("Using a non-vfx asset for visual effect parameter");break;case Xe.Prefab:{const e=await a.getAsset(h);return null==e?(console.error("Using a non-prefab asset for prefab parameter",h),null):new oe(e)}case Xe.PrefabActor:{const e=await a.getAsset(h);return null==e?(console.error("Using a non-prefab asset for prefab parameter",h),null):new le(new oe(e))}case Xe.Sequence:{const e=await a.getAsset(h);if("sequence"===e.type&&"sequence"in e)return new wt(e.sequence);console.error("Using a non-sequence asset for sequence parameter");break}case Xe.Curve:return tt.decode(h);case Xe.ColorLayer:case Xe.MaskLayer:if(ct(h)){const e=await rt.decode(h,async e=>await s.getTexture(await a.getAsset(e))),t=await prepareClassParameters(h.params,null,a,s);return Object.assign(e,t),e}return console.warn("Expecting color layer but got",h),null;case Xe.AnimationClip:{const e="string"==typeof h?h:"object"==typeof h&&null!=h?h.assetId:null;if(null==e)return console.warn("Invalid animation clip asset id value",h),null;return await s.getAnimationClip(await a.getAsset(e))}}return null}function Tt(e){e.updateWorldMatrix(!0,!0),e.updateMatrix(),e.traverse(e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1});const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}function Et(e){return"linear"===e.type?new c(new o(e.color),e.near??100,e.far??1e3):"density"===e.type?new h(e.color,e.density):void console.warn("Invalid fog type",e)}new y({color:4229780});async function Vt(e,t,a,s){null==s&&(s=(new d).identity());const r=s.clone().multiply(kt(e,new i.Matrix4));if(null!=e.children&&e.children.length>0)for(let a=e.children.length-1;a>=0;a--)await Vt(e.children[a],t,e,r);await t(e,a,s)}function kt(e,t){return null==e.position||null==e.rotation||null==e.scale?t.identity():t.compose((new x).fromArray(e.position),(new v).setFromEuler((new l).fromArray(e.rotation)),(new x).fromArray(e.scale))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?Xe.Number:t instanceof F||"function"==typeof e.prototype.isFloat?Xe.FloatNode:t instanceof A||e===A||e.isTexture?Xe.Texture:t instanceof Me||e===q?Xe.Sampler2DNode:t instanceof Boolean||e===Boolean?Xe.Boolean:t instanceof k?Xe.BooleanNode:t instanceof o||e==o?Xe.Color:t instanceof W||"function"==typeof e.prototype.isRgb?Xe.RgbNode:t instanceof S||e==S?Xe.Vector2:t instanceof Q||"function"==typeof e.prototype.isVec2?Xe.Vec2Node:t instanceof x||e==x?Xe.Vector3:t instanceof te||"function"==typeof e.prototype.isVec3?Xe.Vec3Node:t instanceof String||e===String?Xe.String:t instanceof ce||e==ce||e.prototype instanceof ce||e.prototype==ce?Xe.BaseActor:t instanceof l||e==l?Xe.Euler:t instanceof w||e==w?Xe.Object3D:t instanceof u||e==u?Xe.Material:t instanceof AudioBuffer||e==AudioBuffer?Xe.AudioBuffer:t instanceof ne||e==ne?Xe.VisualEffect:t instanceof oe||e==oe?Xe.Prefab:t instanceof le||e==le?Xe.PrefabActor:t instanceof tt||e==tt?Xe.Curve:t instanceof rt||e==rt?Xe.ColorLayer:t instanceof ot||e==ot?Xe.MaskLayer:t instanceof i.AnimationClip||e==i.AnimationClip?Xe.AnimationClip:t instanceof wt||e==wt||"SequenceData"===e.name||e.prototype&&"tracks"in e.prototype?Xe.Sequence:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map(e=>{const s=e.options.array?Xe.Array:toSerializedParamType(e.type),r=e.options.array?toSerializedParamType(e.type):void 0,i=t[e.name];let n=i?.override;void 0===n&&null!=i&&!0===e.options.optional&&(n=!0),void 0===n&&!0===e.options.optional&&(n=!1);const o=function(e,t){if(void 0!==t[e.name])return t[e.name];if(void 0!==e.options.defaultValue){const t=serializeCustomParameter(e.type,e.options.defaultValue);return void 0!==t?t:e.options.defaultValue}return customParameterDefaultValueByType.get(toSerializedParamType(e.type))}(e,a),l=!1!==n||e.options.array?i?.value??(e.options.array?[]:Ft(o)):Ft(o);return[e.name,{type:s,...r?{element:r}:{},value:l,override:n}]}))}function Ot(e){return null!=e&&(!1!==e.override&&(!0===e.override||function(e){return null!=e&&(e.type===Xe.Array?Array.isArray(e.value)?e.value.length>0:null!=e.value:null!=e.value&&""!==e.value)}(e)))}function zt(e){return null==e?{}:Object.fromEntries(Object.entries(e).filter(([,e])=>Ot(e)))}export function prepareCustomParamsFromType(e,t,a=null){const s=Ie(e);if(0===s.length)return{};let r;null!=a?me(a,()=>{r=a.get(e)}):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t&&!0!==e.options.array){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}function Ft(e){return null==e?e:Array.isArray(e)?e.map(e=>Ft(e)):"object"==typeof e?"function"==typeof structuredClone?structuredClone(e):JSON.parse(JSON.stringify(e)):e}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case S:return t instanceof S?t.toArray():void a();case x:return t instanceof x?t.toArray():void a();case I:return t instanceof I?t.toArray():void a();case o:return t instanceof o?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new o(t).getHexString():void a();case String:return t;case l:return t instanceof l?t.toArray():void a();case oe:return t instanceof oe?t.asset?.id??null:void a()}if(t&&"object"==typeof t&&"tracks"in t&&"duration"in t)return t}function Nt(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter(e=>Bt(e.materialId)),(t??[]).filter(e=>Bt(e.materialId)),e=>e.color+e.name)}function Bt(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[Xe.RgbNode,"#000000"],[Xe.Color,"#000000"],[Xe.Vector4,[0,0,0,0]],[Xe.Vec4Node,[0,0,0,0]],[Xe.Vector3,[0,0,0]],[Xe.Vec3Node,[0,0,0]],[Xe.Vector2,[0,0]],[Xe.Vec2Node,[0,0]],[Xe.Euler,[0,0,0,"XYZ"]],[Xe.Array,[]],[Xe.ColorLayer,it],[Xe.MaskLayer,nt]]);let _t=new o;new o;function Ut(e){return null==e?.color?null:(_t.set(e.color),"#"+_t.getHexString())}function $t(e,t,a,s){const r=Ut(e);return null!=r&&(r===t.color&&(e.name===t.name||null==t.name)||a===t.color&&s===t.name)}export function applyMaterial(e,t,a,s){const r=[];return e.traverse(async e=>{if(e instanceof m||e.isMesh||e instanceof i.SkinnedMesh||e.isSkinnedMesh)for(const t of Ce(e.material))t.hasOwnProperty("color")&&r.push(e)}),Promise.all(r.map(async e=>{if(e.material instanceof Array)for(let r=0;r<e.material.length;r++){const i=e.material[r];if(null==i.color||!(i.color instanceof o))continue;const n=Ut(i),l=i.name;if($t(i,t,e.userData["originalColor_"+r],e.userData["originalMaterialName_"+r])){const i=await a(t.materialId),o=e.material[r];null!=i&&o.id!=i.id&&(e.material[r]=i,e.userData["originalColor_"+r]=e.userData["originalColor_"+r]??n,e.userData["originalMaterialName_"+r]=e.userData["originalMaterialName_"+r]??l,null!=s&&s.set(e.id+"#"+r,o))}}else if("color"in e.material){const r=e.material,i=Ut(r),n=r.name;if($t(r,t,e.userData.originalColor,e.userData.originalMaterialName)){const r=await a(t.materialId),o=e.material;null!=r&&(e.material=r,e.userData.originalColor=e.userData.originalColor??i,e.userData.originalMaterialName=e.userData.originalMaterialName??n,null!=s&&(s.has(e.id)||s.set(e.id,o)))}}}))}function Wt(e,t){if(e instanceof i.ShaderMaterial&&t instanceof i.ShaderMaterial){return e.fragmentShader+e.vertexShader==t.fragmentShader+t.vertexShader&&function(e,t){if(e instanceof i.ShaderMaterial&&t instanceof i.ShaderMaterial){for(const a in e.uniforms){if(null==t.uniforms[a])return!1;if(t.uniforms[a].value!==e.uniforms[a].value)return!1}return!0}return!1}(e,t)}return!1}function Lt(e){if(null!=e){for(let t=0;t<e.array.length;t++)e.setX(t,0);e.needsUpdate=!0}}const Rt=new WeakMap;function qt(e){let t=Rt.get(e);return null==t&&(t=function(e){const t=Ve(e);if(null==t)return"";return Object.keys(t.geometry.attributes).sort().join(",")}(e),Rt.set(e,t)),t}const Gt=new WeakMap;function Jt(e){let t=Gt.get(e);return null==t&&(t=function(e){let t=e.type;e instanceof i.MeshStandardMaterial&&!(e instanceof i.MeshPhysicalMaterial)||(t+=e.id+"");(e instanceof i.MeshBasicMaterial||e instanceof i.MeshLambertMaterial||e instanceof y||e instanceof g)&&(null!=e.map&&(t+="c"+e.map?.id),null!=e.aoMap&&(t+="o"+e.aoMap?.id),null!=e.lightMap&&(t+="l"+e.lightMap?.id),null!=e.envMap&&(t+="v"+e.envMap?.id),null!=e.alphaMap&&(t+="a"+e.alphaMap?.id));e instanceof y&&(null!=e.normalMap&&(t+="n"+e.normalMap?.id),null!=e.roughnessMap&&(t+="r"+e.roughnessMap?.id),null!=e.metalnessMap&&(t+="m"+e.metalnessMap?.id),null!=e.emissiveMap&&(t+="e"+e.emissiveMap?.id));e instanceof i.MeshPhysicalMaterial&&(null!=e.sheenColorMap&&(t+="sc"+e.sheenColorMap?.id),null!=e.sheenRoughnessMap&&(t+="sr"+e.sheenRoughnessMap?.id));(e instanceof f||e instanceof g)&&null!=e.specularMap&&(t+="s"+e.specularMap?.id);e instanceof i.MeshToonMaterial&&(null!=e.map&&(t+="c"+e.map?.id),null!=e.aoMap&&(t+="o"+e.aoMap?.id),null!=e.lightMap&&(t+="l"+e.lightMap?.id),null!=e.alphaMap&&(t+="a"+e.alphaMap?.id));e instanceof mt&&null!=e.heightMap&&(t+="h"+e.heightMap?.id);if(e instanceof i.ShaderMaterial){t+=e.vertexShader,t+=e.fragmentShader;for(const a in e.uniforms){const s=e.uniforms[a];s&&s.value&&s.value.isTexture&&null!=s.value.id&&(t+="t:"+a+":"+s.value.id)}}null!=e.userData.outlineParameters&&(t+=e.userData.outlineParameters.color,t+=e.userData.outlineParameters.thickness);return t+=e.side,t+=e.transparent?"t":"",t+=e.vertexColors?"vc":"",t+=e.depthWrite?"dw":"",t+=e.depthTest?"dt":"",t+=e.alphaTest?"at":"",t}(e),Gt.set(e,t)),t}function Ht(e,t){if(null==e)return null;if(!(e instanceof t))throw new Error(`Value is not an instance of ${t.name}`);return e}const Xt=new d,Yt=new l;function Zt(e,t){return Yt.copy(e),Yt.x*=-1,Yt.y*=-1,Yt.z*=-1,t.isCubeTexture&&!1===t.isRenderTargetTexture&&(Yt.y*=-1,Yt.z*=-1),(new i.Matrix3).setFromMatrix4(Xt.makeRotationFromEuler(Yt))}function Kt(e,t){switch(t){case 0:return e.x;case 1:return e.y;case 2:return e.z;case 3:return e.w}}const Qt=new I;function ea(e,t){return e===t||null==e==(null==t)&&("number"==typeof e&&"number"==typeof t?e===t||isNaN(e)&&isNaN(t):e instanceof i.Color&&t instanceof i.Color?e.r===t.r&&e.g===t.g&&e.b===t.b:e instanceof S&&t instanceof S?e.x===t.x&&e.y===t.y:e instanceof x&&t instanceof x?e.x===t.x&&e.y===t.y&&e.z===t.z:e instanceof I&&t instanceof I&&(e.x===t.x&&e.y===t.y&&e.z===t.z&&e.w===t.w))}function ta(e){const t=[];for(const[a,s]of Object.entries(e))s instanceof ne?t.push(s):s instanceof pe&&t.push(...ta(s));return t}function aa(e,t){if(!(t instanceof i.ShaderMaterial)){if(e.deleteAttribute("uv1"),e.hasAttribute("color")){const t=e.getAttribute("color");let a=!0;for(let e=0;e<t.count;e++)for(let s=0;s<3;s++){if(1!=t.getComponent(e,s)){a=!1;break}}a&&e.deleteAttribute("color")}if(e.hasAttribute("uv2")){null!=t.lightMap&&null!=t.aoMap||e.deleteAttribute("uv2")}}}function sa(e,t,a){if(t(e))return e;for(const s of e.children??[]){const e=sa(s,t,a);if(null!=e)return e}if(null!=a&&"prefab"===e.type){const s=a.get(e.assetId);if(null!=s){const e=s.prefab.objects.find(e=>sa(e,t,a));if(null!=e)return e}}return null}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -75,6 +75,8 @@ export declare class ObjectStorage<T extends StorageEntity> {
|
|
|
75
75
|
deleteFile(fileKey: string): Promise<void>;
|
|
76
76
|
private privateObjectPath;
|
|
77
77
|
private privateObjectRelativePath;
|
|
78
|
+
private assertObjectFilePathAvailable;
|
|
79
|
+
private findObjectFilePathCollision;
|
|
78
80
|
private watchDir;
|
|
79
81
|
}
|
|
80
82
|
export declare function tokenizeName(name: string): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{randomUUID as e}from"../../utils/uuid.js";import{pathJoin as t}from"../../utils/files.js";import{combineLatest as a,EMPTY as i,filter as n,firstValueFrom as
|
|
1
|
+
import{randomUUID as e}from"../../utils/uuid.js";import{pathJoin as t}from"../../utils/files.js";import{combineLatest as a,EMPTY as i,filter as n,firstValueFrom as s,from as r,map as h,mergeAll as l,mergeMap as o,Observable as c,of as d,startWith as p,Subject as u,switchMap as f,tap as w}from"rxjs";import{sleepDelay as m}from"../../utils/async.js";const v={},y={},b={},j={};null==v.read&&window.require&&(Object.assign(v,window.require("fs")),Object.assign(y,v.promises),Object.assign(b,window.require("path")),Object.assign(j,window.require("chokidar")));const x=null!=v.existsSync;function F(){if(x){const e="--path=",t=window.process.argv.find(t=>t.startsWith(e));return t?t.substring(e.length):""}return""}const P=/^[A-Z]:/;function g(...e){return 0===e.length?"":P.test(e[0])||x?b.join(...e):t(...e)}export class ObjectStorage{get pathResources(){return g(this.path+"-resources")}constructor(e,t,a=defaultSerializer){this.name=e,this.filePathFn=t,this.serializer=a,this.basePathUpdates=new u,this.basePath=this.basePathUpdates.pipe(h(e=>g(F(),e)),w(e=>{this.path=g(e,this.name),I(this.path),this.determineIfMetaFileShouldBeCreated()})),this.loaded=s(this.basePath),this.shouldCreateIndex=!1}setBasePath(e){this.basePathUpdates.next(e)}async determineIfMetaFileShouldBeCreated(){try{(await y.readFile(g(F(),"vite.config.ts"))).toString().includes("hologyBuild")||(this.shouldCreateIndex=!0)}catch(e){console.warn("Failed to read vite config to determine if meta files should be created")}}async createFolder(e,t=""){C(),await y.mkdir(b.join(this.path,t,e),{recursive:!0})}async deleteFolderForceDangerous(e){await y.rm(b.join(this.path,e),{recursive:!0,force:!0})}async moveFolder(e,t){if(C(),""==e)return void console.warn("Can not move a folder in root");const a=b.resolve(b.join(this.path,t),b.basename(e));if(await E(a)){if(a!==b.resolve(this.path,e))throw new Error("Can not move to directory as a file already exists with the same name")}else{if(function(e,t){const a=b.resolve(e),i=b.resolve(t),n=b.normalize(a)+b.sep;return(b.normalize(i)+b.sep).startsWith(n)}(b.join(this.path,e),b.join(this.path,t)))throw new Error("Can not move a folder into a folder it contains");await y.rename(b.join(this.path,e),a)}}async renameFolder(e,t){await y.rename(b.join(this.path,e),b.resolve(b.dirname(b.join(this.path,e)),t))}async moveToFolder(e,t){if(C(),e.path===t)return;await this.assertObjectFilePathAvailable({...e,path:t},e.id);const a=this.privateObjectPath({...e,path:t});await y.rename(this.privateObjectPath(e),a)}getAbsolutePath(e=""){return b.join(this.path,e)}getResourceAbsolutePath(e=""){return b.join(this.pathResources,e)}watchFolders(){const e=y.readdir(this.path,{recursive:!0,withFileTypes:!0});return a([r(e),this.watchDir(this.path).pipe(n(e=>!e.filename.endsWith(".json")),p(null))]).pipe(f(([e,t])=>null!=t?r(y.readdir(this.path,{recursive:!0,withFileTypes:!0})):d(e)),h(e=>Array.from(new Set(e.filter(e=>e.isDirectory()).map(e=>b.relative(this.path,b.join(e.parentPath,e.name)).replace(/^\.$/,"")).values()))))}watch(){C();r(this.loaded).pipe(f(()=>a([this.watchDir(this.pathResources),r(this.getAll())]).pipe(n(([e])=>null!=e),o(([e,t])=>{if("change"===e.event){const a=b.basename(e.filename),i=t.filter(e=>e.fileKey===a);if(i.length>0)return r(i).pipe(o(e=>{const t=this.privateObjectRelativePath(e);return r(this.readFileIfExists(t)).pipe(h(a=>({event:"change",object:a,path:e.path,filename:t})))}))}return i}))));return r(this.loaded).pipe(f(()=>this.watchDir(this.path)),o(e=>{const t={event:e.event,path:b.dirname(e.filename).replace(/^\.$/,""),filename:b.basename(e.filename)};return e.filename.endsWith(".json")?"unlink"!==e.event?r(this.readFileIfExists(e.filename)).pipe(w(e=>{null!=e&&(null==this.cachedIndex&&(this.cachedIndex={}),this.cachedIndex[e.id]={id:e.id,name:e.name??e.id,path:e.path},this.persistIndex())}),h(e=>({object:e,...t}))):d({object:null,...t}).pipe(w(()=>{const t=Object.keys(this.cachedIndex??{}).find(t=>this.privateObjectRelativePath(this.cachedIndex[t])===e.filename);t&&this.removeIndexEntry(t)})):"change"===e.event?r(this.reloadSubdirectory(e.filename)).pipe(l(),h(e=>({object:e,...t}))):i}))}async reloadSubdirectory(e){return(await this.getAll(e)).filter(t=>t.path.startsWith(e))}async readFileIfExists(e){const t=g(this.path,e);try{const a=await y.readFile(t);return{...JSON.parse(a.toString()),path:b.dirname(e).replace(/^\.$/,""),filename:b.basename(e)}}catch{return console.error("Could not find file at "+t),null}}async getAll(e){if(x){await this.loaded,await I(this.path);const t=(await y.readdir(b.join(this.path,e??""),{recursive:!0,withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(".json")&&!/^[\._]/.test(e.name)),a=100,i=[];for(let e=0;e<t.length;e+=a){const n=t.slice(e,e+a),s=await Promise.all(n.map(e=>y.readFile(g(e.parentPath,e.name)).then(t=>({...JSON.parse(t.toString()),path:b.relative(this.path,e.parentPath).replace(/^\.$/,""),filename:b.basename(e.name)}))));i.push(...s)}return i}const t=await this.loadIndex();return Promise.all(Object.keys(t).map(e=>this.get(e)))}async get(e){const t=await this.loadIndex(),a=t[e]??Object.values(t).find(t=>t.name===e);if(null==a)return;const i=this.privateObjectPath(a);if(!x)return(await fetch(i)).json();return await S(i)?{...JSON.parse((await y.readFile(i)).toString()),path:a.path??"",filename:b.basename(this.privateObjectRelativePath(a))}:null}async save(e){if(C(),await this.loaded,null==e.path){const t=(await this.loadIndex())[e.id];null!=t?.path&&(e={...e,path:t.path})}return await this.assertObjectFilePathAvailable(e,e.id),await y.writeFile(this.privateObjectPath(e),this.serialize(e)),await this.addOrUpdateIndexEntry(e),e}async rename(e,t){const a={...e,name:t};await this.assertObjectFilePathAvailable(a,e.id);const i=this.privateObjectPath(e),n=this.privateObjectPath(a);try{await y.rename(i,n)}catch(e){console.error(e),console.warn("Rename failed, retrying",{currentPath:i,newPath:n}),await m(400),await y.rename(i,n)}return await this.save(a),a}async delete(e){await y.unlink(this.privateObjectPath(e)),this.removeIndexEntry(e.id)}async create(t){C(),await this.loaded,t.id=e();const a=this.privateObjectPath(t);if(await this.assertObjectFilePathAvailable(t),await E(a))throw Error(`Can not create because a file already exists at ${a}`);return await y.writeFile(a,this.serialize(t)),await this.addOrUpdateIndexEntry(t),t}prepareCreate(t){return C(),t.id=e(),t}serialize(e){return this.serializer(e)}async addOrUpdateIndexEntry(e){null==this.cachedIndex&&await this.loadIndex(),this.cachedIndex[e.id]={id:e.id,name:e.name??e.id,path:e.path},await this.persistIndex()}removeIndexEntry(e){null!=this.cachedIndex&&delete this.cachedIndex[e],this.persistIndex()}async persistIndex(){x&&this.shouldCreateIndex&&null!=this.cachedIndex&&await y.writeFile(this.indexFilePath,JSON.stringify(this.cachedIndex,null,2))}get indexFilePath(){return g(this.path,"_meta.json")}async loadIndex(){if(null==this.cachedIndex)if(x){const e=await this.getAll(),t={};for(const a of e)t[a.id]={id:a.id,name:a.name??a.id,path:a.path};this.cachedIndex=t,await this.persistIndex()}else this.cachedIndex=await(await fetch(this.indexFilePath)).json();return this.cachedIndex}async ensureResourceDir(){await I(g(this.path+"-resources"))}async saveFile(e,t){return C(),await I(g(this.path+"-resources")),y.copyFile(t.path,g(this.path+"-resources",e.fileKey))}async saveExtraFile(e,t){return C(),await I(g(this.path+"-resources")),y.copyFile(e,g(this.path+"-resources",t))}getAssetPath(e){return window&&"function"==typeof window.require?window.require("path").join(this.path+"-resources",e.fileKey):g(this.path+"-resources",e.fileKey)}async replaceFile(e,t){if(await S(t))return y.copyFile(t,g(this.path+"-resources",e.fileKey));console.error("Failed to replace file using path "+t)}async deleteFile(e){if(null==e)return;C();const t=g(this.path+"-resources",e);return await S(t)?y.unlink(t):void 0}privateObjectPath(e){return g(this.path,this.privateObjectRelativePath(e))}privateObjectRelativePath(e){return this.filePathFn?g(e.path??"",this.filePathFn(e)):g(e.path??"",tokenizeName(e.name??e.id)+".json")}async assertObjectFilePathAvailable(e,t){const a=await this.findObjectFilePathCollision(e,t);if(null!=a)throw Error(`Can not save "${e.name??e.id}" because "${a.name}" already uses the same storage file name. Use a name that differs beyond letter casing.`)}async findObjectFilePathCollision(e,t){const a=O(this.privateObjectRelativePath(e)),i=await this.loadIndex();return Object.values(i).find(e=>e.id!==t&&O(this.privateObjectRelativePath(e))===a)??null}watchDir(e){return new c(t=>{if("win32"===process.platform&&x){const a=v.watch(e,{recursive:!0},(a,i)=>{if(i){const n=b.join(e,i);v.access(n,v.constants.F_OK,e=>{const n=e?"unlink":"rename"===a?"add":"change";t.next({event:n,filename:i})})}});return()=>a.close()}const a=j.watch(e,{cwd:e,ignoreInitial:!0,disableGlobbing:!0});return a.on("all",(e,a,i)=>{t.next({event:e,filename:a})}),a.on("error",()=>{}),()=>{a.close()}})}}export function tokenizeName(e){return e.trim().replace(/\s/g,"_").replace(/[^a-z0-9_\-\.]/gi,"")}function O(e){return e.replace(/\\/g,"/").toLowerCase()}async function I(e){x&&(await S(e)||await y.mkdir(e,{recursive:!0}))}function S(e){return!!x&&new Promise(function(t,a){v.exists(e,function(e){t(e)})})}function C(){if(!x)throw new Error("Must have direct access to filesystem")}async function E(e){try{await y.access(e,y.constants.F_OK)}catch(e){return!1}return!0}export function defaultSerializer(e){const t={...e};return delete t.path,delete t.filename,JSON.stringify(t,null,2)}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as a}from"tslib";import{Color as t,MeshStandardMaterial as n,Texture as r,Vector2 as i}from"three";import{Shader as o}from"../shader.js";import{Parameter as s}from"../parameter.js";import{removeObjectUndefined as p}from"../../utils/collections.js";import*as d from"three";const l=new r;export class StandardShader extends o{constructor(){super(...arguments),this.color=new t("#FFFFFF"),this.opacity=1,this.roughness=1,this.metalness=0,this.normalScale=new i(1,1),this.sheen=0,this.sheenColor=new t("#FFFFFF"),this.sheenRoughness=.5,this.anisotropy=0,this.heightMap=l,this.vertexColor=!1}build(){const e=this.sheen>0,a=this.anisotropy>0,t=a||e,r=(null!=this.map||null!=this.normalMap)&&null!=this.heightMap&&this.heightMap!=l&&0!==this.heightScale,i=r?ParallaxStandardMaterial:t?d.MeshPhysicalMaterial:n;this.map,null!=this.normalMap&&(this.normalMap.colorSpace=d.LinearSRGBColorSpace),null!=this.metalnessMap&&(this.metalnessMap.colorSpace=d.LinearSRGBColorSpace),null!=this.roughnessMap&&(this.roughnessMap.colorSpace=d.LinearSRGBColorSpace),null!=this.aoMap&&(this.aoMap.colorSpace=d.LinearSRGBColorSpace),null!=this.heightMap&&(this.heightMap.colorSpace=d.NoColorSpace),this.emissiveMap,null!=this.alphaMap&&(this.alphaMap.colorSpace=d.LinearSRGBColorSpace),null!=this.lightMap&&(this.lightMap.colorSpace=d.LinearSRGBColorSpace);return new i(p({color:this.color,vertexColors:this.vertexColor,opacity:this.opacity,roughness:this.roughness,metalness:this.metalness,map:this.map,lightMap:this.lightMap,lightMapIntensity:this.lightMapIntensity,aoMap:this.aoMap,aoMapIntensity:this.aoMapIntensity,emissive:this.emissive,emissiveIntensity:this.emissiveIntensity,emissiveMap:this.emissiveMap,normalMap:this.normalMap,normalScale:this.normalScale,sheen:e?this.sheen:void 0,sheenColor:e?this.sheenColor:void 0,sheenColorMap:e?this.sheenColorMap:void 0,sheenRoughness:e?this.sheenRoughness:void 0,sheenRoughnessMap:e?this.sheenRoughnessMap:void 0,anisotropy:a?this.anisotropy:void 0,anisotropyMap:a?this.anisotropyMap:void 0,anisotropyRotation:a?this.anisotropyRotation:void 0,roughnessMap:this.roughnessMap,metalnessMap:this.metalnessMap,alphaMap:this.alphaMap,envMap:this.envMap,envMapIntensity:this.envMapIntensity,...r?{heightMap:this.heightMap,heightScale:this.heightScale}:{}}))}}e([s(),a("design:type",t)],StandardShader.prototype,"color",void 0),e([s({label:"Color Map"}),a("design:type",r)],StandardShader.prototype,"map",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"opacity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"alphaMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"roughness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"roughnessMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"metalness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"metalnessMap",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"lightMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"lightMapIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"aoMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"aoMapIntensity",void 0),e([s(),a("design:type",t)],StandardShader.prototype,"emissive",void 0),e([s({range:[0,10]}),a("design:type",Number)],StandardShader.prototype,"emissiveIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"emissiveMap",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"normalMap",void 0),e([s(),a("design:type",i)],StandardShader.prototype,"normalScale",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheen",void 0),e([s(),a("design:type",t)],StandardShader.prototype,"sheenColor",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"sheenColorMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheenRoughness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"sheenRoughnessMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"anisotropyRotation",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"anisotropyMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"anisotropy",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"envMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"envMapIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"heightMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"heightScale",void 0),e([s(),a("design:type",Boolean)],StandardShader.prototype,"vertexColor",void 0);export var ParallaxType;!function(e){e[e.none=0]="none",e[e.offset=1]="offset",e[e.pom=2]="pom"}(ParallaxType||(ParallaxType={}));export class ParallaxStandardMaterial extends n{constructor(e={}){super(e),e.heightMap&&(this.heightMap=e.heightMap),this.heightScale=e.heightScale??.05,this.parallaxType=e.parallaxType??ParallaxType.pom,this.minLayers=e.minLayers??10,this.maxLayers=e.maxLayers??32}onBeforeCompile(e){e.uniforms.heightMap={value:this.heightMap},e.uniforms.heightScale={value:this.heightScale},e.uniforms.minLayers={value:this.minLayers},e.uniforms.maxLayers={value:this.maxLayers},e.uniforms.parallaxType={value:this.parallaxType},e.vertexTangents=!0,e.vertexShader=e.vertexShader.replace("#include <uv_pars_vertex>","\n #include <uv_pars_vertex>\n "),e.vertexShader=e.vertexShader.replace("#include <begin_vertex>","\n #include <begin_vertex>\n "),e.fragmentShader=e.fragmentShader.replace("#include <uv_pars_fragment>","\n #include <uv_pars_fragment>\n uniform sampler2D heightMap;\n uniform float heightScale;\n uniform int minLayers;\n uniform int maxLayers;\n uniform int parallaxType;\n\n vec2 parallaxOffset(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 viewDirTS = -viewDir * tbn;\n\n float h = texture(heightMap, uv).r;\n return uv - (viewDirTS.xy / viewDirTS.z) * (h * heightScale);\n }\n\n vec2 parallaxOcclusion2(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 vv = -viewDir * tbn;\n\n float parallaxLimit = -length(vv.xy) / vv.z;\n parallaxLimit *= heightScale;\n\n vec2 vOffsetDir = normalize(vv.xy);\n vec2 vMaxOffset = vOffsetDir * parallaxLimit;\n\n float factor = pow(1.0 - abs(vv.z), 2.0);\n float nNumSamples = mix(float(minLayers), float(maxLayers), factor);\n float fStepSize = 1.0 / nNumSamples;\n\n float fCurrRayHeight = 1.0;\n vec2 vCurrOffset = vec2(0.0);\n vec2 vLastOffset = vec2(0.0);\n float fLastSampledHeight = 1.0;\n float fCurrSampledHeight = 1.0;\n\n for (int nCurrSample = 0; nCurrSample < 128; nCurrSample++) {\n if (float(nCurrSample) > nNumSamples) break;\n\n fCurrSampledHeight = texture2D(heightMap, uv + vCurrOffset).r;\n if (fCurrSampledHeight > fCurrRayHeight) {\n float delta1 = fCurrSampledHeight - fCurrRayHeight;\n float delta2 = (fCurrRayHeight + fStepSize) - fLastSampledHeight;\n float ratio = delta1 / (delta1 + delta2);\n vCurrOffset = ratio * vLastOffset + (1.0 - ratio) * vCurrOffset;\n break;\n } else {\n fCurrRayHeight -= fStepSize;\n vLastOffset = vCurrOffset;\n vCurrOffset += fStepSize * vMaxOffset;\n fLastSampledHeight = fCurrSampledHeight;\n }\n }\n\n return uv + vCurrOffset;\n }\n "),e.fragmentShader=e.fragmentShader.replace("#include <map_fragment>","\n vec3 pomViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n vec2 uvPOM = vMapUv ;\n if (parallaxType == 1) {\n uvPOM = parallaxOffset(vMapUv, pomViewDir, vNormal);\n } else if (parallaxType == 2) {\n uvPOM = parallaxOcclusion2(vMapUv, pomViewDir, vNormal);\n }\n\n vec4 texelColor = texture2D(map, uvPOM);\n diffuseColor *= texelColor;\n "),e.fragmentShader=e.fragmentShader.replace("#include <normal_fragment_maps>","\n #ifdef USE_NORMALMAP\n // RE-COMPUTE TBN for normal mapping consistency\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uvPOM);\n vec2 duv2 = dFdy(uvPOM);\n vec3 dp2perp = cross(dp2, vNormal);\n vec3 dp1perp = cross(vNormal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 localTBN = mat3(T * invmax, B * invmax, vNormal);\n\n vec3 mapN = texture2D(normalMap, uvPOM).xyz * 2.0 - 1.0;\n mapN.xy *= normalScale;\n normal = normalize( localTBN * mapN );\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <roughnessmap_fragment>","\n float roughnessFactor = roughness;\n #ifdef USE_ROUGHNESSMAP\n vec4 texelRoughness = texture2D( roughnessMap, uvPOM );\n // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n roughnessFactor *= texelRoughness.g;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <metalnesssmap_fragment>","\n float metalnessFactor = metalness;\n #ifdef USE_METALNESSMAP\n vec4 texelMetalness = texture2D( metalnessMap, uvPOM );\n // reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n metalnessFactor *= texelMetalness.b;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <aomap_fragment>","\n #ifdef USE_AOMAP\n\n // reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n float ambientOcclusion = ( texture2D( aoMap, uvPOM ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n reflectedLight.indirectDiffuse *= ambientOcclusion;\n\n #if defined( USE_CLEARCOAT ) \n clearcoatSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_SHEEN ) \n sheenSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_ENVMAP ) && defined( STANDARD )\n\n float dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\n reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\n #endif\n\n #endif\n "),this.userData.shader=e}clone(){const e=super.clone();return e.heightMap=this.heightMap,e.heightScale=this.heightScale,e.parallaxType=this.parallaxType,e.minLayers=this.minLayers,e.maxLayers=this.maxLayers,e}}/*
|
|
1
|
+
import{__decorate as e,__metadata as a}from"tslib";import{Color as t,MeshStandardMaterial as n,Texture as r,Vector2 as i}from"three";import{Shader as o}from"../shader.js";import{Parameter as s}from"../parameter.js";import{removeObjectUndefined as p}from"../../utils/collections.js";import*as d from"three";const l=new r;export class StandardShader extends o{constructor(){super(...arguments),this.color=new t("#FFFFFF"),this.opacity=1,this.roughness=1,this.metalness=0,this.normalScale=new i(1,1),this.sheen=0,this.sheenColor=new t("#FFFFFF"),this.sheenRoughness=.5,this.anisotropy=0,this.heightMap=l,this.vertexColor=!1}build(){const e=this.sheen>0,a=this.anisotropy>0,t=a||e,r=(null!=this.map||null!=this.normalMap)&&null!=this.heightMap&&this.heightMap!=l&&0!==this.heightScale,i=r?ParallaxStandardMaterial:t?d.MeshPhysicalMaterial:n;null!=this.map&&(this.map.colorSpace=d.SRGBColorSpace),null!=this.normalMap&&(this.normalMap.colorSpace=d.LinearSRGBColorSpace),null!=this.metalnessMap&&(this.metalnessMap.colorSpace=d.LinearSRGBColorSpace),null!=this.roughnessMap&&(this.roughnessMap.colorSpace=d.LinearSRGBColorSpace),null!=this.aoMap&&(this.aoMap.colorSpace=d.LinearSRGBColorSpace),null!=this.heightMap&&(this.heightMap.colorSpace=d.NoColorSpace),null!=this.emissiveMap&&(this.emissiveMap.colorSpace=d.SRGBColorSpace),null!=this.alphaMap&&(this.alphaMap.colorSpace=d.LinearSRGBColorSpace),null!=this.lightMap&&(this.lightMap.colorSpace=d.LinearSRGBColorSpace);return new i(p({color:this.color,vertexColors:this.vertexColor,opacity:this.opacity,roughness:this.roughness,metalness:this.metalness,map:this.map,lightMap:this.lightMap,lightMapIntensity:this.lightMapIntensity,aoMap:this.aoMap,aoMapIntensity:this.aoMapIntensity,emissive:this.emissive,emissiveIntensity:this.emissiveIntensity,emissiveMap:this.emissiveMap,normalMap:this.normalMap,normalScale:this.normalScale,sheen:e?this.sheen:void 0,sheenColor:e?this.sheenColor:void 0,sheenColorMap:e?this.sheenColorMap:void 0,sheenRoughness:e?this.sheenRoughness:void 0,sheenRoughnessMap:e?this.sheenRoughnessMap:void 0,anisotropy:a?this.anisotropy:void 0,anisotropyMap:a?this.anisotropyMap:void 0,anisotropyRotation:a?this.anisotropyRotation:void 0,roughnessMap:this.roughnessMap,metalnessMap:this.metalnessMap,alphaMap:this.alphaMap,envMap:this.envMap,envMapIntensity:this.envMapIntensity,...r?{heightMap:this.heightMap,heightScale:this.heightScale}:{}}))}}e([s(),a("design:type",t)],StandardShader.prototype,"color",void 0),e([s({label:"Color Map"}),a("design:type",r)],StandardShader.prototype,"map",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"opacity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"alphaMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"roughness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"roughnessMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"metalness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"metalnessMap",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"lightMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"lightMapIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"aoMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"aoMapIntensity",void 0),e([s(),a("design:type",t)],StandardShader.prototype,"emissive",void 0),e([s({range:[0,10]}),a("design:type",Number)],StandardShader.prototype,"emissiveIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"emissiveMap",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"normalMap",void 0),e([s(),a("design:type",i)],StandardShader.prototype,"normalScale",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheen",void 0),e([s(),a("design:type",t)],StandardShader.prototype,"sheenColor",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"sheenColorMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheenRoughness",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"sheenRoughnessMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"anisotropyRotation",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"anisotropyMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"anisotropy",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"envMap",void 0),e([s({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"envMapIntensity",void 0),e([s(),a("design:type",r)],StandardShader.prototype,"heightMap",void 0),e([s(),a("design:type",Number)],StandardShader.prototype,"heightScale",void 0),e([s(),a("design:type",Boolean)],StandardShader.prototype,"vertexColor",void 0);export var ParallaxType;!function(e){e[e.none=0]="none",e[e.offset=1]="offset",e[e.pom=2]="pom"}(ParallaxType||(ParallaxType={}));export class ParallaxStandardMaterial extends n{constructor(e={}){super(e),e.heightMap&&(this.heightMap=e.heightMap),this.heightScale=e.heightScale??.05,this.parallaxType=e.parallaxType??ParallaxType.pom,this.minLayers=e.minLayers??10,this.maxLayers=e.maxLayers??32}onBeforeCompile(e){e.uniforms.heightMap={value:this.heightMap},e.uniforms.heightScale={value:this.heightScale},e.uniforms.minLayers={value:this.minLayers},e.uniforms.maxLayers={value:this.maxLayers},e.uniforms.parallaxType={value:this.parallaxType},e.vertexTangents=!0,e.vertexShader=e.vertexShader.replace("#include <uv_pars_vertex>","\n #include <uv_pars_vertex>\n "),e.vertexShader=e.vertexShader.replace("#include <begin_vertex>","\n #include <begin_vertex>\n "),e.fragmentShader=e.fragmentShader.replace("#include <uv_pars_fragment>","\n #include <uv_pars_fragment>\n uniform sampler2D heightMap;\n uniform float heightScale;\n uniform int minLayers;\n uniform int maxLayers;\n uniform int parallaxType;\n\n vec2 parallaxOffset(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 viewDirTS = -viewDir * tbn;\n\n float h = texture(heightMap, uv).r;\n return uv - (viewDirTS.xy / viewDirTS.z) * (h * heightScale);\n }\n\n vec2 parallaxOcclusion2(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 vv = -viewDir * tbn;\n\n float parallaxLimit = -length(vv.xy) / vv.z;\n parallaxLimit *= heightScale;\n\n vec2 vOffsetDir = normalize(vv.xy);\n vec2 vMaxOffset = vOffsetDir * parallaxLimit;\n\n float factor = pow(1.0 - abs(vv.z), 2.0);\n float nNumSamples = mix(float(minLayers), float(maxLayers), factor);\n float fStepSize = 1.0 / nNumSamples;\n\n float fCurrRayHeight = 1.0;\n vec2 vCurrOffset = vec2(0.0);\n vec2 vLastOffset = vec2(0.0);\n float fLastSampledHeight = 1.0;\n float fCurrSampledHeight = 1.0;\n\n for (int nCurrSample = 0; nCurrSample < 128; nCurrSample++) {\n if (float(nCurrSample) > nNumSamples) break;\n\n fCurrSampledHeight = texture2D(heightMap, uv + vCurrOffset).r;\n if (fCurrSampledHeight > fCurrRayHeight) {\n float delta1 = fCurrSampledHeight - fCurrRayHeight;\n float delta2 = (fCurrRayHeight + fStepSize) - fLastSampledHeight;\n float ratio = delta1 / (delta1 + delta2);\n vCurrOffset = ratio * vLastOffset + (1.0 - ratio) * vCurrOffset;\n break;\n } else {\n fCurrRayHeight -= fStepSize;\n vLastOffset = vCurrOffset;\n vCurrOffset += fStepSize * vMaxOffset;\n fLastSampledHeight = fCurrSampledHeight;\n }\n }\n\n return uv + vCurrOffset;\n }\n "),e.fragmentShader=e.fragmentShader.replace("#include <map_fragment>","\n vec3 pomViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n vec2 uvPOM = vMapUv ;\n if (parallaxType == 1) {\n uvPOM = parallaxOffset(vMapUv, pomViewDir, vNormal);\n } else if (parallaxType == 2) {\n uvPOM = parallaxOcclusion2(vMapUv, pomViewDir, vNormal);\n }\n\n vec4 texelColor = texture2D(map, uvPOM);\n diffuseColor *= texelColor;\n "),e.fragmentShader=e.fragmentShader.replace("#include <normal_fragment_maps>","\n #ifdef USE_NORMALMAP\n // RE-COMPUTE TBN for normal mapping consistency\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uvPOM);\n vec2 duv2 = dFdy(uvPOM);\n vec3 dp2perp = cross(dp2, vNormal);\n vec3 dp1perp = cross(vNormal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 localTBN = mat3(T * invmax, B * invmax, vNormal);\n\n vec3 mapN = texture2D(normalMap, uvPOM).xyz * 2.0 - 1.0;\n mapN.xy *= normalScale;\n normal = normalize( localTBN * mapN );\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <roughnessmap_fragment>","\n float roughnessFactor = roughness;\n #ifdef USE_ROUGHNESSMAP\n vec4 texelRoughness = texture2D( roughnessMap, uvPOM );\n // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n roughnessFactor *= texelRoughness.g;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <metalnesssmap_fragment>","\n float metalnessFactor = metalness;\n #ifdef USE_METALNESSMAP\n vec4 texelMetalness = texture2D( metalnessMap, uvPOM );\n // reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n metalnessFactor *= texelMetalness.b;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <aomap_fragment>","\n #ifdef USE_AOMAP\n\n // reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n float ambientOcclusion = ( texture2D( aoMap, uvPOM ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n reflectedLight.indirectDiffuse *= ambientOcclusion;\n\n #if defined( USE_CLEARCOAT ) \n clearcoatSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_SHEEN ) \n sheenSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_ENVMAP ) && defined( STANDARD )\n\n float dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\n reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\n #endif\n\n #endif\n "),this.userData.shader=e}clone(){const e=super.clone();return e.heightMap=this.heightMap,e.heightScale=this.heightScale,e.parallaxType=this.parallaxType,e.minLayers=this.minLayers,e.maxLayers=this.maxLayers,e}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{expect as e,test as
|
|
1
|
+
import{expect as e,test as n}from"vitest";import{BoxGeometry as t,Euler as o,Group as s,Mesh as i,MeshBasicMaterial as a,Quaternion as r,Vector3 as c}from"three";import{importCollisionShapes as l}from"../scene/collision/collision-shape-import.js";import{BoxCollisionShape as m,CollisionShapeSource as d,toInstancedCollisionShape as p}from"../scene/collision/collision-shape.js";import{calculateOBB as w}from"../utils/obb-utils.js";function u(n,t,o=1e-5){e(n.distanceTo(t)).toBeLessThan(o)}function f(n,t,o=1e-5){e(n.angleTo(t)).toBeLessThan(o)}n("box import keeps a stable local-axis box and composes only the mesh transform",()=>{const n=new s,o=new t(4,1,2);o.rotateX(.2),o.rotateY(.65),o.translate(.4,-.15,.3);const p=new i(o,new a);p.position.set(3,-2,1),p.rotation.set(.35,1.1,-.45),p.scale.set(1.5,1,.75),n.add(p),n.updateMatrixWorld(!0);o.computeBoundingBox();const w=o.boundingBox,h=w.getCenter(new c),x=w.getSize(new c),b=x.clone().multiply(p.scale),[y]=l(n,{mesh:{collisions:{shapeType:"box"}}}),B=y,E=h.clone().multiply(p.scale).applyQuaternion(p.quaternion).add(p.position);e(B).toBeInstanceOf(m),e(B.source).toBe(d.rendered),u(B.dimensions,b),u(B.offset,E),f((new r).setFromEuler(B.rotation),p.quaternion),u(B.instancedDimensions,x),u(B.instancedOffset,h),f((new r).setFromEuler(B.instancedRotation),new r)}),n("box import bakes scaled parent transforms into dimensions",()=>{const e=new s,n=new s,o=new i(new t(100,50,2),new a);n.scale.set(.01,.02,.5),n.add(o),e.add(n),e.updateMatrixWorld(!0);const[r]=l(e,{mesh:{collisions:{shapeType:"box"}}}),m=r;u(m.dimensions,new c(1,1,1)),u(m.instancedDimensions,new c(100,50,2))}),n("obb import composes the mesh transform with the local OBB transform",()=>{const n=new s,o=new t(4,1,2);o.rotateX(.2),o.rotateY(.65),o.translate(.4,-.15,.3);const c=new i(o,new a);c.position.set(3,-2,1),c.rotation.set(.35,1.1,-.45),c.scale.set(1.5,1,.75),n.add(c),n.updateMatrixWorld(!0);const[p]=l(n,{mesh:{collisions:{shapeType:"obb"}}}),h=p,x=w(o),b=x.center.clone().multiply(c.scale).applyQuaternion(c.quaternion).add(c.position),y=c.quaternion.clone().multiply((new r).setFromEuler(x.rotation));e(h).toBeInstanceOf(m),e(h.source).toBe(d.rendered),u(h.offset,b),f((new r).setFromEuler(h.rotation),y),u(h.instancedOffset,x.center),f((new r).setFromEuler(h.instancedRotation),(new r).setFromEuler(x.rotation))}),n("convex import keeps a rotated child mesh transform exactly once",()=>{const e=new s,n=new s,o=new i(new t(1,2,3),new a);o.rotation.set(-Math.PI/2,0,0),n.add(o),e.add(n),e.updateMatrixWorld(!0);const[c]=l(e,{mesh:{collisions:{shapeType:"convex"}}});f((new r).setFromEuler(c.rotation),o.quaternion)}),n("instanced collision shapes use the mesh-local transform without mutating the cached shape",()=>{const n=new m(new c(1,2,3));n.source=d.rendered,n.offset.set(10,11,12),n.rotation.set(.4,.5,.6),n.instancedOffset=new c(1,2,3),n.instancedRotation=new o(.1,.2,.3),n.instancedDimensions=new c(.25,.5,.75);const t=p(n);e(t).not.toBe(n),u(t.dimensions,n.instancedDimensions),u(t.offset,n.instancedOffset),f((new r).setFromEuler(t.rotation),(new r).setFromEuler(n.instancedRotation)),u(n.offset,new c(10,11,12)),u(n.dimensions,new c(1,2,3)),f((new r).setFromEuler(n.rotation),(new r).setFromEuler(new o(.4,.5,.6)))});/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as e,expect as a,it as t,vi as o}from"vitest";import*as r from"three";import{createCameraClipInstance as n,createCameraTrack as s,createSequenceData as i,createTransformKeyframe as c,createTransformSubTrack as l,SequenceRole as m}from"../effects/sequence/sequence-data.js";import{SequencePlayer as p}from"../effects/sequence/sequence-player.js";import{BaseActor as d}from"../gameplay/actors/actor.js";function u(e){const a=new p;return a.setWorld({scene:new r.Scene}),a.setViewController(e),a}async function C(e){const{ViewController:a}=await import("../gameplay/services/render.js");return new a({camera:e,running:!1,paused:!1,onLoop:o.fn(),setCamera(e){this.camera=e},stop:o.fn()})}function f(e,a,t){const o=s(),r=n(a,t);r.blendInDuration=0,r.blendOutDuration=0,o.clips.push(r);const i=l(),m=c(a);return m.position=e,i.keyframes.push(m),o.subTracks.push(i),o}o.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,a)=>(a in e||(e[a]=("string"!=typeof a||!a.startsWith("is"))&&o.fn()),e[a]),set:(e,a,t)=>(e[a]=t,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),e("sequencer camera control",()=>{t("keeps setCamera as the base camera while an override lease is active",async()=>{const e=new r.PerspectiveCamera,t=new r.PerspectiveCamera,o=new r.PerspectiveCamera,n=await C(e),s=n.pushCameraOverride(t,{});a(n.getCamera()).toBe(t),n.setCamera(o),a(n.getBaseCamera()).toBe(o),a(n.getCamera()).toBe(t),s.release(),a(n.getCamera()).toBe(o)}),t("does not take over the local camera unless camera control is enabled",async()=>{const e=new r.PerspectiveCamera,t=await C(e),o=u(t),n=f([5,0,0],0,1);o.load({...i(),duration:1,tracks:[n]}),o.play(),a(t.getCamera()).toBe(e)}),t("activates an opted-in camera shot and releases it after the clip",async()=>{const e=new r.PerspectiveCamera,t=await C(e),o=u(t),n=f([5,2,1],0,1);o.cameraControlEnabled=!0,o.load({...i(),duration:2,tracks:[n]}),o.play(),a(t.getCamera()).not.toBe(e),a(t.getCamera().position.toArray()).toEqual([5,2,1]),o.seek(1.1),a(t.getCamera()).toBe(e)}),t("uses the later camera track when shots overlap",async()=>{const e=new r.PerspectiveCamera,t=await C(e),o=u(t),n=f([1,0,0],0,1),s=f([7,0,0],0,1);o.cameraControlEnabled=!0,o.load({...i(),duration:1,tracks:[n,s]}),o.play(),a(t.getCamera().position.x).toBeCloseTo(7)}),t("blends into the camera shot using the clip blend settings",async()=>{const e=new r.PerspectiveCamera;e.position.set(0,0,0);const t=await C(e),o=u(t),n=f([10,0,0],0,2);n.clips[0].blendInDuration=1,n.clips[0].blendInterpolation="linear",o.cameraControlEnabled=!0,o.load({...i(),duration:2,tracks:[n]}),o.play(),o.seek(.5),a(t.getCamera().position.x).toBeCloseTo(5)}),t("anchors camera tracks to bound roles",async()=>{const e=new r.PerspectiveCamera,t=await C(e),o=u(t),n=new w;n.object.position.set(10,0,0);const s=f([1,0,0],0,1);s.parentRole=m.Self,o.cameraControlEnabled=!0,o.bindRole(m.Self,n),o.load({...i(),duration:1,tracks:[s]}),o.play(),a(t.getCamera().position.x).toBeCloseTo(11)})});class w extends d{}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as e,expect as t,it as o}from"vitest";import{Color as r,Euler as a,Vector3 as l}from"three";import{canTrackAddSubTrack as s,createPropertyKeyframe as n,createPropertySubTrack as p,createSpawnTrack as i,evaluateCustomParamValueKeyframes as u,SequencePlayer as y}from"../effects/sequence/index.js";import{SerializedParamType as g}from"../scene/model.js";e("sequence property parameter tracks",()=>{o("allows multiple property sub-tracks on spawn tracks but rejects duplicate property paths",()=>{const e=i(),o=p({propertyPath:"settings.globalGain",propertyType:g.Vector3});t(s(e,"property",{propertyPath:"settings.globalGain"})).toBe(!0),e.subTracks.push(o),t(s(e,"property",{propertyPath:"settings.globalGain"})).toBe(!1),t(s(e,"property",{propertyPath:"settings.globalGamma"})).toBe(!0)}),o("interpolates number, vector, color, and Euler property keyframes",()=>{const e=u([n(0,{type:g.Number,value:0}),n(1,{type:g.Number,value:10})],.5);t(e?.value).toBeCloseTo(5);const o=u([n(0,{type:g.Vector3,value:[0,0,0]}),n(1,{type:g.Vector3,value:[2,4,6]})],.5,{min:0,max:3});t(o?.value).toEqual([1,2,3]);const a=u([n(0,{type:g.Color,value:"#000000"}),n(1,{type:g.Color,value:"#ffffff"})],.5);t(a?.value).toBe(`#${new r("#000000").lerp(new r("#ffffff"),.5).getHexString()}`);const l=u([n(0,{type:g.Euler,value:[0,0,0,"XYZ"]}),n(1,{type:g.Euler,value:[1,2,3,"XYZ"]})],.5);t(l?.value).toEqual([.5,1,1.5,"XYZ"])}),o("uses step evaluation for booleans and options-backed values",()=>{const e=u([n(0,{type:g.Boolean,value:!1}),n(1,{type:g.Boolean,value:!0})],.5,{stepOnly:!0});t(e?.value).toBe(!1);const o=u([n(0,{type:g.Number,value:1}),n(1,{type:g.Number,value:2})],.5,{stepOnly:!0});t(o?.value).toBe(1)}),o("applies nested property paths and restores an original undefined value",()=>{const e={settings:{globalGain:void 0}},o=p({propertyPath:"settings.globalGain",propertyType:g.Vector3}),r=new y;r.applyResolvedPropertyValue(o,e,{type:g.Vector3,value:[1,2,3]}),t(e.settings.globalGain).toBeInstanceOf(l),t(e.settings.globalGain?.toArray()).toEqual([1,2,3]),r.stop(),t(Object.prototype.hasOwnProperty.call(e.settings,"globalGain")).toBe(!0),t(e.settings.globalGain).toBeUndefined()}),o("mutates existing mutable values and restores their original value",()=>{const e=new l(9,8,7),o=new r("#112233"),s=new a(.1,.2,.3,"XYZ"),n={settings:{globalGain:e,colorTint:o,rotation:s}},i=new y;i.applyResolvedPropertyValue(p({propertyPath:"settings.globalGain",propertyType:g.Vector3}),n,{type:g.Vector3,value:[1,2,3]}),i.applyResolvedPropertyValue(p({propertyPath:"settings.colorTint",propertyType:g.Color}),n,{type:g.Color,value:"#ffffff"}),i.applyResolvedPropertyValue(p({propertyPath:"settings.rotation",propertyType:g.Euler}),n,{type:g.Euler,value:[1,2,3,"XYZ"]}),t(n.settings.globalGain).toBe(e),t(n.settings.globalGain.toArray()).toEqual([1,2,3]),t(n.settings.colorTint).toBe(o),t(n.settings.colorTint.getHexString()).toBe("ffffff"),t(n.settings.rotation).toBe(s),t(n.settings.rotation.toArray()).toEqual([1,2,3,"XYZ"]),i.stop(),t(n.settings.globalGain).toBe(e),t(n.settings.globalGain.toArray()).toEqual([9,8,7]),t(n.settings.colorTint).toBe(o),t(n.settings.colorTint.getHexString()).toBe("112233"),t(n.settings.rotation).toBe(s),t(n.settings.rotation.toArray()).toEqual([.1,.2,.3,"XYZ"])})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{afterEach as e,beforeEach as t,describe as a,expect as r,it as o,vi as i}from"vitest";import{createRequire as s}from"node:module";import*as n from"node:fs/promises";import*as c from"node:os";import*as d from"node:path";const w=s(import.meta.url);let l,f,m;async function p(){const{ObjectStorage:e}=await import("../scene/storage/storage.js"),t=new e("asset");return t.setBasePath("data"),t}a("ObjectStorage case-insensitive file collisions",()=>{t(async()=>{i.resetModules(),f=window.require,m=window.process,l=await n.mkdtemp(d.join(c.tmpdir(),"hology-storage-")),await n.writeFile(d.join(l,"vite.config.ts"),"hologyBuild()"),Object.defineProperty(window,"require",{configurable:!0,value:e=>"chokidar"===e?{watch:()=>({on:()=>{},close:()=>{}})}:w(e)}),Object.defineProperty(window,"process",{configurable:!0,value:{argv:[`--path=${l}`]}})}),e(async()=>{await n.rm(l,{recursive:!0,force:!0}),Object.defineProperty(window,"require",{configurable:!0,value:f}),Object.defineProperty(window,"process",{configurable:!0,value:m})}),o("rejects create names that only differ by case",async()=>{const e=await p();await e.create({name:"dirt"}),await r(e.create({name:"Dirt"})).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects prepared saves that only differ by case",async()=>{const e=await p();await e.create({name:"dirt"});const t=e.prepareCreate({name:"Dirt"});await r(e.save(t)).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects renames that only differ by case from another object",async()=>{const e=await p();await e.create({name:"dirt"});const t=await e.create({name:"sand"});await r(e.rename(t,"Dirt")).rejects.toThrow(/differs beyond letter casing/),await r(e.get(t.id)).resolves.toMatchObject({name:"sand"})})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|