@tomtom-org/maps-sdk-plugin-landmarks-3d 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1 +1 @@
1
- import{LayerFilterComposer,MERCATOR_UNITS_PER_EPSG3857_METER,StylingFoundationsModule,configWithKnobs,configWithoutKnob,knobValueIn,localFrameMatrix,parseCssColor,standardStyleIDs}from"@tomtom-org/maps-sdk/map";import{MercatorCoordinate}from"maplibre-gl";import{AmbientLight,Box2,BufferAttribute,BufferGeometry,Camera,Color,CustomBlending,DataArrayTexture,DirectionalLight,DoubleSide,FrontSide,Group,HemisphereLight,LinearFilter,LinearMipmapLinearFilter,LoaderUtils,LoadingManager,MathUtils,Mesh,MeshBasicMaterial,MeshLambertMaterial,OneFactor,OneMinusSrcAlphaFactor,PCFSoftShadowMap,PlaneGeometry,RedFormat,RepeatWrapping,SRGBColorSpace,Scene,ShaderMaterial,ShadowMaterial,ShapeUtils,UnsignedByteType,Vector2,Vector3,Vector4,WebGLRenderer}from"three";import{TomTomConfig,isProxyCredentialsMode}from"@tomtom-org/maps-sdk/core";import{MeshoptDecoder}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{GLTFLoader}from"three/examples/jsm/loaders/GLTFLoader.js";import{KTX2Loader}from"three/examples/jsm/loaders/KTX2Loader.js";import{toCreasedNormals}from"three/examples/jsm/utils/BufferGeometryUtils.js";var BUILDING_GROUPS=["education","transport","leisure","healthcare","shopping"],oneColorForEveryGroup=e=>new Array(BUILDING_GROUPS.length+1).fill(e),groupColorsOfPaint=e=>{if("string"==typeof e)return oneColorForEveryGroup(e);if(!Array.isArray(e)||"match"!==e[0])return;const t=e.at(-1);if("string"!=typeof t)return;const i=e.slice(2,-1);return[...BUILDING_GROUPS.map(e=>{for(let t=0;t<i.length;t+=2){const[n,a]=[i[t],i[t+1]];if((Array.isArray(n)?n.includes(e):n===e)&&"string"==typeof a)return a}return t}),t]},landmarksOn=/* @__PURE__ */new WeakMap,buildings3DLookOn=/* @__PURE__ */new WeakMap,restyleLandmarksOn=/* @__PURE__ */new WeakMap,isMesh=e=>!0===e.isMesh,parsedCssColors=/* @__PURE__ */new Map,setCssColor=(e,t)=>{const i=(e=>{if(parsedCssColors.has(e))return parsedCssColors.get(e);parsedCssColors.size>=64&&parsedCssColors.clear();const t=parseCssColor(e);return parsedCssColors.set(e,t),t})(t);return i?e.setRGB(i[0],i[1],i[2],SRGBColorSpace):e},whenMapReady=(e,t)=>{e.mapReady?t():e.mapLibreMap.once("styledata",()=>whenMapReady(e,t))},sameLook=(e,t)=>void 0!==t&&JSON.stringify(e)===JSON.stringify(t),setMaterialOpacity=(e,t)=>{e.opacity=t;const i=t<1;i!==e.transparent&&(e.transparent=i,e.needsUpdate=!0)},mercatorMetresToLngLat=(e,t)=>new MercatorCoordinate(.5+e*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t*MERCATOR_UNITS_PER_EPSG3857_METER).toLngLat().toArray(),setCameraProjection=(e,t)=>{e.projectionMatrix.fromArray(t),e.projectionMatrixInverse.copy(e.projectionMatrix).invert()},DAY={opacity:1,minZoom:15,"facade.pattern":"mixed","facade.intensity":.85,"facade.floorHeightMeters":3.4,"windows.color":"#8da3b6","reflections.intensity":.7,"litWindows.color":"#ffd08a","litWindows.fraction":0,"litWindows.intensity":.8,"light.direction":215,"light.altitude":30,"light.color":"#fff3e0","light.intensity":.75,"ambientLight.color":"#dce8f5","ambientLight.intensity":.45,"shadows.visible":!0,"shadows.intensity":.7,"roadLabels.occluded":!1,"pois.occluded":!1},NIGHT=/* @__PURE__ */(()=>({...DAY,"facade.intensity":.9,"windows.color":"#1a2330","litWindows.color":"#f2c98f","litWindows.fraction":.3,"litWindows.intensity":.35,"light.direction":135,"light.altitude":35,"light.color":"#a9bde0","light.intensity":.3,"ambientLight.color":"#5a6c94","ambientLight.intensity":.5,"shadows.intensity":.4}))(),PRESETS=/* @__PURE__ */(()=>({streetLight:DAY,streetDark:NIGHT,streetLightDriving:{...DAY,"facade.intensity":.55,"shadows.intensity":.5},streetDarkDriving:{...NIGHT,"facade.intensity":.7,"litWindows.fraction":.2},monoLight:{...DAY,"facade.intensity":.6,"windows.color":"#b4b9bf","light.color":"#ffffff","ambientLight.color":"#f2f4f7","ambientLight.intensity":.55,"shadows.intensity":.5},monoDark:{...NIGHT,"facade.intensity":.75,"windows.color":"#1f2226","litWindows.color":"#d3dae4","litWindows.fraction":.2,"litWindows.intensity":.3,"light.color":"#c7d0de","ambientLight.color":"#565d68"},streetSatellite:{...DAY,"facade.intensity":1,"walls.color":"#d8d0c2","roofs.color":"#8f8a82","windows.color":"#647b90","light.color":"#fff0d4","light.intensity":.8,"light.altitude":35,"shadows.intensity":.75}}))(),towardsSun=(e,t=new Vector3)=>{const i=MathUtils.degToRad(e["light.direction"]),n=MathUtils.degToRad(e["light.altitude"]);return t.set(Math.sin(i)*Math.cos(n),Math.cos(i)*Math.cos(n),Math.sin(n))},isDrawn=(e,t)=>!0!==e.underground&&!0!==e.has_part&&!1!==e.extrude&&!(t.withoutLandmarks&&!0===e.has_landmark),numberOr=(e,t)=>"number"==typeof e?e:t,seedOf=(e,t)=>{const i=e.id??`${t[0]?.[0]?.x},${t[0]?.[0]?.y}`;let n=2166136261;for(const a of String(i))n=Math.imul(n^(a.codePointAt(0)??0),16777619);return(n>>>0)/2**32},GROUP_INDEX=/* @__PURE__ */(()=>new Map(BUILDING_GROUPS.map((e,t)=>[e,t])))(),readBuildings=(e,t,i)=>{const n=e.latestFeatureIndex?.loadVTLayers()[t];if(!n?.length)return{footprints:[],extent:4096};const a=[];for(let o=0;o<n.length;o++){const e=n.feature(o);if(3!==e.type||!isDrawn(e.properties,i))continue;const t=e.loadGeometry();a.push({rings:t,base:numberOr(e.properties.ground_height,0),height:numberOr(e.properties.height,4),group:GROUP_INDEX.get(e.properties.group)??BUILDING_GROUPS.length,seed:seedOf(e,t)})}return{footprints:a,extent:n.extent??n.feature(0).extent}},FACADE_ATTRIBUTES={uv:"facadeUv",frame:"facadeFrame",kind:"facadeKind"},ROOF_NORMAL=[0,0,1],signedArea=e=>{let t=0;for(let i=0,n=e.length-1;i<e.length;n=i++)t+=(e[n].x-e[i].x)*(e[i].y+e[n].y);return t/2},isBorderEdge=(e,t,i)=>e.x<=0&&t.x<=0||e.x>=i&&t.x>=i||e.y<=0&&t.y<=0||e.y>=i&&t.y>=i,insideTile=(e,t,i)=>{let n=0,a=1;const o=t.x-e.x,r=t.y-e.y,s=[[-o,e.x],[o,i-e.x],[-r,e.y],[r,i-e.y]];for(const[l,d]of s){if(0===l){if(d<0)return;continue}const e=d/l;l<0?n=Math.max(n,e):a=Math.min(a,e)}return n<a?[n,a]:void 0},GeometryWriter=class{attributeSizes=[["position",3],["normal",3],[FACADE_ATTRIBUTES.uv,2],[FACADE_ATTRIBUTES.frame,4],[FACADE_ATTRIBUTES.kind,2]];count=0;capacity=4096;arrays=this.allocate();normal=ROOF_NORMAL;frame=[0,0,0,0];roof=0;group=0;startSurface(e,t,i,n){this.normal=e,this.frame=t,this.roof=i,this.group=n}vertex(e,t,i,n,a){if(this.count===this.capacity){this.capacity*=2;const e=this.arrays;this.arrays=this.allocate();for(const[t]of this.attributeSizes)this.arrays[t].set(e[t])}const o=this.count++,{normal:r,frame:s,roof:l,group:d}=this,{position:c,normal:h,[FACADE_ATTRIBUTES.uv]:m}=this.arrays,u=this.arrays[FACADE_ATTRIBUTES.frame],f=this.arrays[FACADE_ATTRIBUTES.kind];c[3*o]=e,c[3*o+1]=t,c[3*o+2]=i,h[3*o]=r[0],h[3*o+1]=r[1],h[3*o+2]=r[2],m[2*o]=n,m[2*o+1]=a,u[4*o]=s[0],u[4*o+1]=s[1],u[4*o+2]=s[2],u[4*o+3]=s[3],f[2*o]=l,f[2*o+1]=d}toGeometry(){const e=new BufferGeometry;for(const[t,i]of this.attributeSizes)e.setAttribute(t,new BufferAttribute(this.arrays[t].slice(0,this.count*i),i));return e.computeBoundingSphere(),e}allocate(){return Object.fromEntries(this.attributeSizes.map(([e,t])=>[e,new Float32Array(this.capacity*t)]))}},writeWalls=(e,t,i,n,a)=>{const{base:o,height:r,seed:s,group:l}=n,d=i.length-1,c=i[0].equals(i[d])?d:i.length;for(let h=0;h<c;h++){const n=(h+1)%i.length;if(isBorderEdge(t[h],t[n],a))continue;const d=insideTile(t[h],t[n],a);if(!d)continue;const c=i[h],m=i[n],u=c.distanceTo(m);if(0===u)continue;const f=m.x-c.x,g=m.y-c.y,p=[g/u,-f/u,0],[y,v]=d,w=y>0||v<1,x=w?(c.x*f+c.y*g)/u:0;e.startSurface(p,[w?0:u,o,r,s],0,l);const b=(t,i)=>e.vertex(c.x+f*t,c.y+g*t,i,x+t*u,i);b(y,o),b(v,o),b(v,r),b(y,o),b(v,r),b(y,r)}},clipToTile=(e,t)=>{const i=[e=>e.x,e=>t-e.x,e=>e.y,e=>t-e.y];let n=e;for(const a of i){const e=n;n=[],e.forEach((t,i)=>{const o=e[(i||e.length)-1],[r,s]=[a(t),a(o)];if(r>=0!=s>=0){const e=s/(s-r);n.push({x:o.x+(t.x-o.x)*e,y:o.y+(t.y-o.y)*e})}r>=0&&n.push(t)})}return n},writeRoof=(e,t,i,n)=>{if(t.length<3)return;const a=ShapeUtils.triangulateShape(t,i),o=[t,...i].flat(),{height:r,group:s}=n;e.startSurface(ROOF_NORMAL,[0,n.base,r,n.seed],1,s);const l=t=>e.vertex(t.x,t.y,r,t.x,t.y);for(const[d,c,h]of a){const e=o[d],t=o[c],i=o[h],n=(t.x-e.x)*(i.y-e.y)-(t.y-e.y)*(i.x-e.x)>0;l(e),l(n?t:i),l(n?i:t)}},writeBuilding=(e,t,i)=>{if(t.height<=t.base)return;const n=e=>new Vector2(i.originX+e.x*i.metresPerUnit,i.originY-e.y*i.metresPerUnit);for(const[a,...o]of(e=>{const t=[];let i;for(const n of e){const e=signedArea(n);0!==e&&(i??=e<0,i===e<0?t.push([n]):t.at(-1)?.push(n))}return t})(t.rings)){const r=(e,t)=>{const i=e.map(n);return signedArea(i)>0!==t?{tileRing:[...e].reverse(),sceneRing:[...i].reverse()}:{tileRing:e,sceneRing:i}},s=r(a,!0),l=o.map(e=>r(e,!1));for(const n of[s,...l])writeWalls(e,n.tileRing,n.sceneRing,t,i.extent);const d=e=>clipToTile(e,i.extent).map(n),c=o.map(d).filter(e=>e.length>=3);writeRoof(e,d(a),c,t)}},BuildingsExtrusion=class{buildings;frame;writer=new GeometryWriter;next=0;constructor(e,t){this.buildings=e,this.frame=t}extrudeUntil(e){do{if(this.next===this.buildings.length)break;writeBuilding(this.writer,this.buildings[this.next++],this.frame)}while(performance.now()<e);return this.next===this.buildings.length}toGeometry(){return this.writer.toGeometry()}},GLASS_GLSL="\nuniform vec3 eyePosition;\nuniform vec3 sunDirection;\nuniform vec3 sunColor;\nuniform vec3 skyColor;\nuniform float skyIntensity;\nuniform float reflectivity;\nconst float SKY_GLOW = 0.5;\nconst float SUN_GLOW = 0.6;\n\n\n\nvec3 mirroredSky(vec3 direction) {\nvec2 heading = normalize(direction.xy + 1e-4);\nvec3 sky = skyColor * skyIntensity * mix(3.0, 1.8, smoothstep(0.0, 0.7, direction.z));\nfloat sunSide = max(dot(heading, normalize(sunDirection.xy + 1e-4)), 0.0);\nreturn sky + sunColor * SKY_GLOW * sunSide * sunSide * (1.0 - smoothstep(0.0, 0.6, direction.z)) * (1.0 - sunDirection.z);\n}\n\n\nvec3 mirroredStreet() {\nreturn (skyColor * skyIntensity + sunColor * sunDirection.z * smoothstep(0.35, 0.75, sunDirection.z)) * 0.25;\n}\n\n\nvec3 mirroredSun(vec3 reflected) {\nreturn sunColor * pow(max(dot(reflected, sunDirection), 0.0), 12.0) * SUN_GLOW;\n}\n\n\nfloat glassFresnel(vec3 normal, vec3 toEye) {\nreturn 0.25 + 0.75 * pow(1.0 - clamp(dot(normal, toEye), 0.0, 1.0), 5.0);\n}\n",SUN_IN_THE_GLASS="\n#if NUM_DIR_LIGHTS > 0\nvec3 glassSunSeen = directLight.color / max(directionalLights[0].color, vec3(1e-4));\ntotalEmissiveRadiance += glassSunReflection * clamp(max(glassSunSeen.r, max(glassSunSeen.g, glassSunSeen.b)), 0.0, 1.0);\n#endif\n",WINDOW_LAYOUTS=[{across:[.29,.71],up:[.3,.78]},{across:[.1,.9],up:[.22,.8]},{across:[.05,.95],up:[.04,.95]},{across:[.06,.94],up:[.09,.85]}],coverage=(e,[t,i])=>Math.max(0,Math.min(e+1,128*i)-Math.max(e,128*t)),createWindowProfiles=()=>{const e=new Uint8Array(128*WINDOW_LAYOUTS.length*2);WINDOW_LAYOUTS.flatMap(({across:e,up:t})=>[e,t]).forEach((t,i)=>{for(let n=0;n<128;n++)e[128*i+n]=Math.round(255*coverage(n,t))});const t=new DataArrayTexture(e,128,1,2*WINDOW_LAYOUTS.length);return t.format=RedFormat,t.type=UnsignedByteType,t.wrapS=RepeatWrapping,t.magFilter=LinearFilter,t.minFilter=LinearMipmapLinearFilter,t.generateMipmaps=!0,t.needsUpdate=!0,t},GROUP_COLOR_COUNT=BUILDING_GROUPS.length+1,PATTERN_INDEX={plain:0,residential:1,office:2,glass:3,mixed:4},VERTEX_DECLARATIONS$1=/* @__PURE__ */(()=>`\nattribute vec2 ${FACADE_ATTRIBUTES.uv};\nattribute vec4 ${FACADE_ATTRIBUTES.frame};\nattribute vec2 ${FACADE_ATTRIBUTES.kind};\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n`)(),VERTEX_ASSIGNMENTS$1=/* @__PURE__ */(()=>`\nvFacadeUv = ${FACADE_ATTRIBUTES.uv};\nvFacadeFrame = ${FACADE_ATTRIBUTES.frame};\nvFacadeKind = ${FACADE_ATTRIBUTES.kind};\nvScenePosition = (modelMatrix * vec4(transformed, 1.0)).xyz;\nvSceneNormal = normalize(mat3(modelMatrix) * objectNormal);\n`)(),FRAGMENT_DECLARATIONS$1=/* @__PURE__ */(()=>`\nuniform vec3 wallColors[${GROUP_COLOR_COUNT}];\nuniform vec3 roofColor;\nuniform float roofFollowsWalls;\nuniform vec3 windowColor;\nuniform vec3 litColor;\nuniform float litFraction;\nuniform float litIntensity;\nuniform float facadeIntensity;\nuniform float floorHeight;\nuniform float facadePattern;\n${GLASS_GLSL}\nconst float GLINT_SHARPNESS = 160.0;\nconst float GLINT_STRENGTH = 2.0;\nconst float PANE_TILT = 0.04;\n\nconst float PANE_LIFT = 0.1;\n\nconst float STREET_WIDTH = 24.0;\nconst float ACROSS_WIDTH = 28.0;\n\n\nconst float ACROSS_BAY = 3.0;\nconst vec2 ACROSS_GLASS = vec2(0.6, 0.55);\nuniform sampler2DArray windowProfiles;\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n\n\nfloat facadeHash(vec3 point) {\npoint = fract(point * 0.1031);\npoint += dot(point, point.zyx + 31.32);\nreturn fract((point.x + point.y) * point.z);\n}\n\n\nfloat facadeBayWidth(float pattern) {\nreturn pattern < 1.5 ? 3.2 : (pattern < 2.5 ? 3.0 : 1.6);\n}\n\n\n\nfloat cellCoverage(float x, float share, float footprint) {\nfloat covered = 1.0 - smoothstep(-footprint, footprint, abs(fract(x) - 0.5) - share * 0.5);\nreturn mix(covered, share, smoothstep(0.25, 0.6, footprint));\n}\n\n\n\n\n\nvec3 mirroredWorld(vec3 direction, vec3 wallNormal, vec3 wallAlong, vec2 spot, vec3 wall, float building, float top, float metresPerPixel, float eyeDistance) {\nvec3 skyLight = skyColor * skyIntensity;\nvec2 heading = normalize(direction.xy + 1e-4);\nfloat travel = STREET_WIDTH * (0.7 + 0.6 * facadeHash(vec3(building, 2.0, 5.0))) / max(dot(direction, wallNormal), 0.05);\nvec2 met = spot + vec2(dot(direction, wallAlong), direction.z) * travel;\nfloat footprint = metresPerPixel * (1.0 + travel / eyeDistance);\nfloat blur = max(footprint, 0.3);\nvec3 across = vec3(floor(met.x / ACROSS_WIDTH), building, 7.0);\nfloat acrossTop = max(top, 12.0) * (0.5 + 0.9 * facadeHash(across));\n\n\nfloat facesSun = max(dot(-heading, sunDirection.xy), 0.0)\n* smoothstep(-blur, blur, met.y - acrossTop * (1.0 - smoothstep(0.1, 0.8, sunDirection.z)));\n\nfloat tone = 0.45 + 0.5 * facadeHash(across + 3.1);\nvec2 cell = met / vec2(ACROSS_BAY, floorHeight);\nfloat glass = cellCoverage(cell.x, ACROSS_GLASS.x, footprint / ACROSS_BAY)\n* cellCoverage(cell.y, ACROSS_GLASS.y, footprint / floorHeight);\nfloat lit = mix(step(facadeHash(vec3(floor(cell), building + 11.0)), litFraction), litFraction,\nsmoothstep(0.25, 0.6, footprint / ACROSS_BAY));\nvec3 facades = mix(wall * tone, windowColor, glass) * (skyLight + sunColor * facesSun)\n+ litColor * litIntensity * lit * glass * 0.8;\nvec3 seen = mix(mirroredStreet(), facades, smoothstep(-blur, blur, met.y));\nreturn mix(seen, mirroredSky(direction), smoothstep(acrossTop - blur, acrossTop + blur, met.y));\n}\n\n\nvoid applyFacade(inout vec3 albedo, out vec3 emissive, out vec3 sunReflection) {\nemissive = vec3(0.0);\nsunReflection = vec3(0.0);\nfloat wallLength = vFacadeFrame.x;\nfloat base = vFacadeFrame.y;\nfloat top = vFacadeFrame.z;\nfloat seed = vFacadeFrame.w;\n\nfloat building = floor(seed * 4096.0 + 0.5);\nvec3 wall = wallColors[int(clamp(vFacadeKind.y + 0.5, 0.0, ${GROUP_COLOR_COUNT-1}.0))] * (0.94 + 0.12 * seed);\nfloat height = vFacadeUv.y;\n\nfloat pattern = facadePattern;\nif (pattern > 3.5) {\npattern = top >= 50.0 ? 3.0 : (top >= 18.0 ? (seed < 0.3 ? 3.0 : 2.0) : 1.0);\n}\nfloat bayWidth = facadeBayWidth(pattern);\n\nfloat bays = wallLength > 0.0 ? floor(wallLength / bayWidth + 0.5) : 1.0;\nfloat along = vFacadeUv.x / (wallLength > 0.0 ? wallLength / max(bays, 1.0) : bayWidth);\nfloat bay = floor(along);\nfloat groundFloor = base < 0.5 && top >= 10.0 ? floorHeight * 1.35 : 0.0;\nfloat storeys = floor((top - 0.8 - base - groundFloor) / floorHeight);\nfloat storey = (height - base - groundFloor) / floorHeight;\nbool onGroundFloor = height < base + groundFloor;\nfloat floorIndex = onGroundFloor ? -1.0 : floor(storey);\nfloat onFloor = onGroundFloor ? 1.0 : step(0.0, floorIndex) * step(floorIndex + 0.5, storeys);\nfloat windowLayout = onGroundFloor ? ${WINDOW_LAYOUTS.length-1}.0 : pattern - 1.0;\nfloat upStorey = onGroundFloor ? (height - base) / max(groundFloor, 1e-3) : storey;\n\n\nfloat window = texture(windowProfiles, vec3(along, 0.5, windowLayout * 2.0)).r\n* texture(windowProfiles, vec3(upStorey, 0.5, windowLayout * 2.0 + 1.0)).r * onFloor;\n\n\n\n\nfloat bayAveraged = smoothstep(0.3, 0.7, fwidth(along));\nfloat storeyAveraged = smoothstep(0.3, 0.7, fwidth(storey));\nfloat distant = max(bayAveraged, storeyAveraged);\n\n\nfloat panesSharp = 1.0 - smoothstep(0.08, 0.25, max(fwidth(along), fwidth(storey)));\nfloat metresPerPixel = max(fwidth(vFacadeUv.x), fwidth(vFacadeUv.y));\n\nif (vFacadeKind.x > 0.5) {\nvec3 roof = mix(roofColor, wall * 0.8, roofFollowsWalls);\nalbedo = roof * (0.97 + 0.06 * facadeHash(vec3(floor(vFacadeUv / 3.0), building)));\nreturn;\n}\n\n\nfloat occlusion = mix(0.7, 1.0, smoothstep(0.0, 12.0, height));\nalbedo = wall * occlusion;\nif (pattern < 0.5 || top < 2.5 || bays < 1.0) return;\n\nvec3 windowSeed = vec3(bay, floorIndex, building);\nvec3 glass = windowColor * mix(0.85 + 0.3 * facadeHash(windowSeed), 1.0, distant);\n\nvec3 between = pattern > 2.5 ? mix(wall, windowColor, 0.45) * occlusion : albedo;\nfloat strength = window * facadeIntensity;\nalbedo = mix(between, glass, strength);\n\nvec3 wallNormal = normalize(vSceneNormal);\n\nvec3 wallAlong = vec3(-wallNormal.y, wallNormal.x, 0.0);\n\nvec2 tilt = (vec2(facadeHash(windowSeed + 5.3), facadeHash(windowSeed + 8.9)) - 0.5) * vec2(PANE_TILT, PANE_LIFT) * panesSharp;\nvec3 normal = normalize(wallNormal + tilt.x * wallAlong + vec3(0.0, 0.0, tilt.y));\nfloat eyeDistance = distance(eyePosition, vScenePosition);\nvec3 toEye = (eyePosition - vScenePosition) / eyeDistance;\nvec3 reflected = reflect(-toEye, normal);\n\nfloat mirror = reflectivity * (pattern > 2.5 ? 1.0 : 0.57) * strength;\nfloat reflectance = mirror * glassFresnel(normal, toEye);\n\nalbedo *= 1.0 - reflectance;\nemissive += mirroredWorld(reflected, wallNormal, wallAlong, vFacadeUv, wall, building, top, metresPerPixel, eyeDistance)\n* reflectance;\n\nsunReflection = sunColor * pow(max(dot(reflected, sunDirection), 0.0), GLINT_SHARPNESS) * GLINT_STRENGTH * mirror\n+ mirroredSun(reflected) * reflectance;\n\nfloat litWindow = 1.0 - step(litFraction, facadeHash(windowSeed + 13.7));\n\nfloat litFloor = min(1.0, litFraction * (0.1 + 1.8 * facadeHash(vec3(-1.0, floorIndex, building))));\nfloat lit = mix(mix(litWindow, litFloor, bayAveraged), litFraction, storeyAveraged);\n\nfloat glow = mix(mix(0.65 + 0.35 * facadeHash(windowSeed + 3.1), 0.2, bayAveraged), 0.15, storeyAveraged);\nemissive += litColor * litIntensity * lit * strength * glow;\nalbedo *= 1.0 - 0.6 * lit * strength;\n}\n`)(),toVector=(e,t=new Vector3)=>{const i=setCssColor(new Color,e);return t.set(i.r,i.g,i.b)},FacadeMaterial=class extends MeshLambertMaterial{facadeUniforms={wallColors:{value:Array.from({length:GROUP_COLOR_COUNT},()=>new Vector3(1,1,1))},roofColor:{value:new Vector3(1,1,1)},roofFollowsWalls:{value:1},windowColor:{value:new Vector3},litColor:{value:new Vector3},litFraction:{value:0},litIntensity:{value:0},facadeIntensity:{value:1},floorHeight:{value:3.4},facadePattern:{value:PATTERN_INDEX.mixed},skyColor:{value:new Vector3(1,1,1)},skyIntensity:{value:.45},reflectivity:{value:.7},sunDirection:{value:new Vector3(0,0,1)},sunColor:{value:new Vector3(1,1,1)},eyePosition:{value:new Vector3},windowProfiles:{value:createWindowProfiles()}};constructor(){super(),this.onBeforeCompile=e=>{Object.assign(e.uniforms,this.facadeUniforms),e.vertexShader=e.vertexShader.replace("#include <common>",`#include <common>\n${VERTEX_DECLARATIONS$1}`).replace("#include <begin_vertex>",`#include <begin_vertex>\n${VERTEX_ASSIGNMENTS$1}`),e.fragmentShader=e.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS$1}`).replace("#include <map_fragment>","#include <map_fragment>\nvec3 facadeEmissive;\nvec3 glassSunReflection;\napplyFacade(diffuseColor.rgb, facadeEmissive, glassSunReflection);").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += facadeEmissive;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setLook(e){const t=this.facadeUniforms;e.wallColorsByGroup.forEach((e,i)=>toVector(e,t.wallColors.value[i])),toVector(e["roofs.color"],t.roofColor.value),t.roofFollowsWalls.value=e.roofsFollowWalls?1:0,toVector(e["windows.color"],t.windowColor.value),toVector(e["litWindows.color"],t.litColor.value),t.litFraction.value=e["litWindows.fraction"],t.litIntensity.value=1.4*e["litWindows.intensity"],t.facadeIntensity.value=e["facade.intensity"],t.floorHeight.value=e["facade.floorHeightMeters"],t.facadePattern.value=PATTERN_INDEX[e["facade.pattern"]],toVector(e["ambientLight.color"],t.skyColor.value),t.skyIntensity.value=e["ambientLight.intensity"],t.reflectivity.value=e["reflections.intensity"],towardsSun(e,t.sunDirection.value),toVector(e["light.color"],t.sunColor.value).multiplyScalar(e["light.intensity"]),setMaterialOpacity(this,e.opacity)}setEyePosition(e){this.facadeUniforms.eyePosition.value.copy(e)}},BuildingsLayer=class{landmarksOf;id;type="custom";renderingMode="3d";source={id:"vectorTiles",layer:"buildings"};map;renderer;look;filter={withoutLandmarks:!1};origin;frame=0;scene=new Scene;camera=new Camera;buildings=new Group;landmarks=new Group;material=new FacadeMaterial;depthOnly=new MeshBasicMaterial({colorWrite:!1});shadowsOnly=new MeshBasicMaterial({colorWrite:!1,depthWrite:!1});sun=new DirectionalLight;sky=new HemisphereLight;groundReach={value:5e3};ground=new Mesh(new PlaneGeometry(1,1),this.groundMaterial());tiles=/* @__PURE__ */new Map;pending=[];extrusion;constructor(e,t=()=>{}){this.landmarksOf=t,this.id=e,this.sky.position.set(0,0,1),this.sun.castShadow=!0,this.sun.shadow.bias=-4e-4,this.sun.shadow.normalBias=.4,this.ground.receiveShadow=!0,this.ground.renderOrder=1,this.landmarks.matrixAutoUpdate=!1,this.scene.add(this.buildings,this.landmarks,this.sun,this.sun.target,this.sky,this.ground)}setLook(e){this.look=e,this.material.setLook(e),setCssColor(this.sun.color,e["light.color"]),this.sun.intensity=e["light.intensity"]*Math.PI,setCssColor(this.sky.color,e["ambientLight.color"]),this.sky.groundColor.copy(this.sky.color).multiplyScalar(.45),this.sky.intensity=e["ambientLight.intensity"]*Math.PI,this.sun.shadow.intensity=e["shadows.intensity"],this.ground.visible=e["shadows.visible"]}onAdd(e,t){this.map=e,this.renderer??=new WebGLRenderer({canvas:e.getCanvas(),context:t,antialias:!0}),this.renderer.autoClear=!1,this.renderer.shadowMap.type=PCFSoftShadowMap;const i=Math.min(4096,this.renderer.capabilities.maxTextureSize);this.sun.shadow.mapSize.set(i,i)}render(e,t){const{map:i,renderer:n,look:a}=this;if(!i||!n||!a?.visible)return;const o=t.defaultProjectionData.mainMatrix,r=this.landmarksOf(),s=r?.prepareForBuildings(o,this.material.facadeUniforms);if(this.buildings.visible=i.getZoom()>=a.minZoom,this.landmarks.visible=void 0!==s,!this.buildings.visible&&!s)return;this.frame++;const l=void 0!==s;l!==this.filter.withoutLandmarks&&(this.filter={withoutLandmarks:l},this.pending=[],this.extrusion=void 0);const d=this.updateOrigin(i);this.buildings.visible&&this.updateTiles(i,d),r&&s&&this.placeLandmarks(r,s,d),setCameraProjection(this.camera,localFrameMatrix(o,d.position,{centerLatitude:i.getCenter().lat})),this.material.setEyePosition(this.eyePosition()),this.updateSun(i,d,a),n.shadowMap.enabled!==a["shadows.visible"]&&(n.shadowMap.enabled=a["shadows.visible"],this.scene.traverse(e=>{if(isMesh(e))for(const t of[e.material].flat())t.needsUpdate=!0})),n.resetState(),n.setViewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight);const c=[{group:this.buildings,translucent:a.opacity<1,use:e=>this.useBuildingsPass(e)}];r&&s&&c.push({group:this.landmarks,translucent:s.translucent,use:e=>r.useMaterials(e)}),c.some(({translucent:e})=>e)?this.renderTranslucent(n,c):n.render(this.scene,this.camera)}renderTranslucent(e,t){const i=t.filter(e=>e.translucent),n=t.filter(e=>!e.translucent),a=n.map(({group:e})=>e.visible),o=this.ground.visible;if(this.ground.visible=!1,n.length){for(const e of i)e.use("shadows");e.render(this.scene,this.camera);for(const{group:e}of n)e.visible=!1}e.shadowMap.autoUpdate=!1;for(const r of i)r.use("depth");e.render(this.scene,this.camera),this.ground.visible=o,e.shadowMap.autoUpdate=!n.length;for(const r of i)r.use("color");e.render(this.scene,this.camera),n.forEach(({group:e},t)=>{e.visible=a[t]}),e.shadowMap.autoUpdate=!0}useBuildingsPass(e){const t={color:this.material,depth:this.depthOnly,shadows:this.shadowsOnly}[e];for(const{mesh:i}of this.tiles.values())i.material=t}placeLandmarks(e,t,i){e.tiles.parent!==this.landmarks&&this.landmarks.add(e.tiles);const n=i.metresPerMercator*MERCATOR_UNITS_PER_EPSG3857_METER,a=this.toScene(i,.5+t.origin.x*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t.origin.y*MERCATOR_UNITS_PER_EPSG3857_METER);this.landmarks.matrix.makeScale(n,n,1).setPosition(a.x,a.y,0),this.landmarks.matrixWorldNeedsUpdate=!0}toScene(e,t,i){return new Vector2((t-e.x)*e.metresPerMercator,(e.y-i)*e.metresPerMercator)}updateOrigin(e){const t=e.getCenter(),i=MercatorCoordinate.fromLngLat(t);if(this.origin&&this.toScene(this.origin,i.x,i.y).length()<2e4)return this.origin;const n=this.origin;return this.origin={x:i.x,y:i.y,position:t.toArray(),metresPerMercator:Math.cos(MathUtils.degToRad(t.lat))/MERCATOR_UNITS_PER_EPSG3857_METER},n&&this.carryTiles(n,this.origin),this.pending=[],this.extrusion=void 0,this.origin}carryTiles(e,t){const i=t.metresPerMercator/e.metresPerMercator,n=this.toScene(t,e.x,e.y);for(const{mesh:a}of this.tiles.values())a.position.set(a.position.x*i+n.x,a.position.y*i+n.y,0),a.scale.set(a.scale.x*i,a.scale.y*i,1)}updateTiles(e,t){const i=((e,t,i,n)=>{const a=e.style?.tileManagers?.[t],o=/* @__PURE__ */new Map;for(const r of a?.getRenderableIds()??[]){const e=a?.getTileByID(r);if(!e?.latestFeatureIndex?.rawTileData)continue;const{x:t,y:s,z:l}=e.tileID.canonical,{wrap:d}=e.tileID,c=`${l}/${t}/${s}/${d}`;o.has(c)||o.set(c,{key:c,x:t,y:s,z:l,wrap:d,read:()=>readBuildings(e,i,n)})}return[...o.values()]})(e,this.source.id,this.source.layer,this.filter),n=new Set(i.map(({key:e})=>e));this.queueTiles(i,n,t);const a=performance.now()+(e.isMoving()?4:8);for(;this.pending.length&&performance.now()<a;){const e=this.pending[0];if(this.extrusion?.key!==e.key&&(this.extrusion={key:e.key,run:this.startExtrusion(e,t)}),!this.extrusion.run.extrudeUntil(a))break;this.pending.shift();const i=this.tiles.get(e.key);i&&this.removeTileMesh(i.mesh),this.tiles.set(e.key,{mesh:this.addTileMesh(this.extrusion.run),lastSeen:this.frame,withoutLandmarks:this.filter.withoutLandmarks,origin:t}),this.extrusion=void 0}this.pending.length&&e.triggerRepaint();for(const[o,{mesh:r}]of this.tiles)r.visible=n.has(o);this.evictStaleTiles()}queueTiles(e,t,i){const n=new Set(this.pending.map(({key:e})=>e));for(const a of e){const e=this.tiles.get(a.key);e&&(e.lastSeen=this.frame),e?.withoutLandmarks===this.filter.withoutLandmarks&&e.origin===i||n.has(a.key)||this.pending.push(a)}this.pending=this.pending.filter(({key:e})=>t.has(e))}startExtrusion(e,t){const{footprints:i,extent:n}=e.read(),a=2**e.z,o=this.toScene(t,e.wrap+e.x/a,e.y/a);return new BuildingsExtrusion(i,{extent:n,originX:o.x,originY:o.y,metresPerUnit:t.metresPerMercator/(a*n)})}addTileMesh(e){const t=new Mesh(e.toGeometry(),this.material);return t.castShadow=!0,t.receiveShadow=!0,this.buildings.add(t),t}removeTileMesh(e){this.buildings.remove(e),e.geometry.dispose()}evictStaleTiles(){if(this.tiles.size<=96)return;const e=[...this.tiles].sort(([,e],[,t])=>e.lastSeen-t.lastSeen);for(const[t,{mesh:i}]of e.slice(0,this.tiles.size-96))i.visible||(this.removeTileMesh(i),this.tiles.delete(t))}eyePosition(){const e=new Vector4(0,0,1,0).applyMatrix4(this.camera.projectionMatrixInverse);return 0===e.w?new Vector3:new Vector3(e.x/e.w,e.y/e.w,e.z/e.w)}groundMaterial(){const e=new ShadowMaterial({opacity:.55,depthWrite:!1});return e.onBeforeCompile=e=>{e.uniforms.groundReach=this.groundReach,e.vertexShader=e.vertexShader.replace("#include <common>","#include <common>\nvarying vec2 vGroundUv;").replace("#include <begin_vertex>","#include <begin_vertex>\nvGroundUv = uv;"),e.fragmentShader=e.fragmentShader.replace("#include <common>","#include <common>\nuniform float groundReach;\nvarying vec2 vGroundUv;").replace("#include <fog_fragment>","gl_FragColor.a *= 1.0 - smoothstep(4000.0, 5000.0, length(vGroundUv * 2.0 - 1.0) * groundReach);\n#include <fog_fragment>")},e}updateSun(e,t,i){const n=MercatorCoordinate.fromLngLat(e.getCenter()),a=this.toScene(t,n.x,n.y);this.sun.target.position.set(a.x,a.y,0),this.sun.position.set(a.x,a.y,0).addScaledVector(towardsSun(i),8e3),this.sun.updateMatrixWorld(),this.sun.target.updateMatrixWorld();const{clientWidth:o,clientHeight:r}=e.getCanvas(),s=((e,t)=>{const i=e.getPitch(),n=t/2/Math.tan(MathUtils.degToRad(e.getVerticalFieldOfView())/2)*Math.min(.85*Math.tan(MathUtils.degToRad(90-i)),Math.tan(MathUtils.degToRad(89.25-i)));return Math.max(0,t/2-n)})(e,r),l=[[0,s],[o,s],[o,r],[0,r]].map(([i,n])=>{const o=MercatorCoordinate.fromLngLat(e.unproject([i,n]));return this.toScene(t,o.x,o.y).sub(a).clampLength(0,5e3).add(a)}),{shadow:d}=this.sun;d.updateMatrices(this.sun);const c=new Box2;for(const p of l){const e=new Vector3(p.x,p.y,0).applyMatrix4(d.camera.matrixWorldInverse);c.expandByPoint(new Vector2(e.x,e.y))}c.expandByScalar(150);const h=c.getSize(new Vector2).divideScalar(100).ceil().multiplyScalar(100),m=h.clone().divide(d.mapSize),u=(new Vector3).applyMatrix4(d.camera.matrixWorldInverse),f=c.min.clone().sub(u).divide(m).floor().multiply(m).add(u);d.camera.left=f.x,d.camera.right=f.x+h.x,d.camera.bottom=f.y,d.camera.top=f.y+h.y,d.camera.near=1,d.camera.far=16e3,d.camera.updateProjectionMatrix();const g=Math.max(...l.map(e=>e.distanceTo(a)))+150;this.groundReach.value=g,this.ground.position.set(a.x,a.y,.05),this.ground.scale.set(2*g,2*g,1)}},LAYER_ID="tomtom-3d-buildings",Buildings3D=class{map;buildingsLayer;config;renderedLook;styling;occludedLabels=/* @__PURE__ */new Set;styleOrder=[];constructor(e,t={}){this.map=e,this.config=t,this.buildingsLayer=new BuildingsLayer(LAYER_ID,()=>landmarksOn.get(e)),buildings3DLookOn.set(e,()=>{const e=this.look();return e.visible?e:void 0}),this.render(),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{this.map.mapReady&&!sameLook(this.look(),this.renderedLook)?this.render():this.styling&&this.placeLabels()}),whenMapReady(e,()=>this.install())}get layer(){return this.buildingsLayer}getConfig(){return structuredClone(this.config)}applyConfig(e){this.config=e,this.render()}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_knobValue(e){return this.look()[e]}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}install(){const e=this.map.mapLibreMap,t=e.getLayer("3D - Building");t?.source&&t.sourceLayer&&(this.buildingsLayer.source={id:t.source,layer:t.sourceLayer}),e.getLayer(LAYER_ID)||(this.occludedLabels.clear(),e.addLayer(this.buildingsLayer,t?"3D - Building":e.getLayersOrder().find(t=>"symbol"===e.getLayer(t)?.type))),this.render()}look(){const e=this.map.mapLibreMap,t=this.map.mapReady&&e.getLayer("3D - Building")?e.getPaintProperty("3D - Building","fill-extrusion-color"):void 0;return((e,t)=>{const i=e.preset??"auto",n=PRESETS["auto"===i?t.style:i],a=t=>knobValueIn(e,t)??n[t],o=e.walls?.color??n["walls.color"],r=o?oneColorForEveryGroup(o):t.styleColors??oneColorForEveryGroup("hsl(38, 6%, 90%)"),s=e.roofs?.color??n["roofs.color"],l=r[BUILDING_GROUPS.length];return{visible:e.visible??!0,preset:i,opacity:a("opacity"),minZoom:a("minZoom"),"facade.pattern":a("facade.pattern"),"facade.intensity":a("facade.intensity"),"facade.floorHeightMeters":a("facade.floorHeightMeters"),"walls.color":l,"roofs.color":s??l,"windows.color":a("windows.color"),"reflections.intensity":a("reflections.intensity"),"litWindows.color":a("litWindows.color"),"litWindows.fraction":a("litWindows.fraction"),"litWindows.intensity":a("litWindows.intensity"),"light.direction":a("light.direction"),"light.altitude":a("light.altitude"),"light.color":a("light.color"),"light.intensity":a("light.intensity"),"ambientLight.color":a("ambientLight.color"),"ambientLight.intensity":a("ambientLight.intensity"),"shadows.visible":a("shadows.visible"),"shadows.intensity":a("shadows.intensity"),"roadLabels.occluded":a("roadLabels.occluded"),"pois.occluded":a("pois.occluded"),wallColorsByGroup:r,roofsFollowWalls:void 0===s}})(this.config,{style:(i=this.map.getStyleInput(),("string"==typeof i?i:i?.id)??"streetLight"),styleColors:groupColorsOfPaint(t)});var i}render(){const e=this.look();this.renderedLook=e,this.buildingsLayer.setLook(e),restyleLandmarksOn.get(this.map)?.(),this.map.mapReady&&(this.map.mapLibreMap.getLayer("3D - Building")&&LayerFilterComposer.for(this.map).setClause("3D - Building","landmarks3d.buildings3D",!e.visible&&void 0),e.visible&&(e["roadLabels.occluded"]||e["pois.occluded"])&&(this.styling??=StylingFoundationsModule.get(this.map)),(this.styling||this.occludedLabels.size)&&this.placeLabels(),this.map.mapLibreMap.triggerRepaint())}async placeLabels(){const e=await this.styling,t=this.renderedLook,i=this.map.mapLibreMap;if(!e||!t||!i.getLayer(LAYER_ID))return;const n=(i,n)=>t.visible&&n?e.layers.query({group:i}).layerIds:[],a=/* @__PURE__ */new Set([...n("roadLabels",t["roadLabels.occluded"]),...n("pois",t["pois.occluded"])]),o=i.getLayersOrder(),r=o.indexOf(LAYER_ID);[...this.occludedLabels].some(e=>o.indexOf(e)>r)&&this.occludedLabels.clear(),this.restoreLabels(a),this.occludeLabels(a)}restoreLabels(e){const t=this.map.mapLibreMap;for(const i of this.occludedLabels){if(e.has(i))continue;this.occludedLabels.delete(i);const n=this.styleOrder.slice(this.styleOrder.indexOf(i)+1).find(e=>!this.occludedLabels.has(e)&&t.getLayer(e));t.getLayer(i)&&t.moveLayer(i,n)}}occludeLabels(e){const t=this.map.mapLibreMap,i=t.getLayersOrder(),n=i.indexOf(LAYER_ID);for(const a of e){const e=i.indexOf(a);if(!(this.occludedLabels.has(a)||e<n)){if(this.occludedLabels.size){if(!this.styleOrder.includes(a)){const t=this.styleOrder.indexOf(i[e+1]);this.styleOrder.splice(t<0?this.styleOrder.length:t,0,a)}}else this.styleOrder=[...i];this.occludedLabels.add(a),t.moveLayer(a,LAYER_ID)}}}},UNIT_RANGE={min:0,max:1,step:.05,bounds:"hard"},withIds=e=>Object.keys(e).map(t=>({id:t,...e[t]})),facadePatterns=["mixed","residential","office","glass","plain"],buildingsPresets=/* @__PURE__ */(()=>["auto",...standardStyleIDs])(),buildings3DKnobCatalogue=/* @__PURE__ */withIds({visible:{kind:"toggle",description:"The 3D buildings.",default:!0},preset:{kind:"enum",description:"Look every unset knob takes: a standard style's, or auto, which follows the map's standard style.",options:buildingsPresets,default:"auto"},opacity:{kind:"number",description:"Opacity of the buildings, and of the landmarks left unset among them, 0 to 1.",range:UNIT_RANGE},minZoom:{kind:"number",description:"Lowest zoom the buildings are drawn at, and the landmarks left unset among them.",range:{min:13,max:22,step:1,bounds:"hard"}},"facade.pattern":{kind:"enum",description:"How windows are laid out: mixed (by building height), residential, office, glass (curtain walls) or plain (no windows).",options:facadePatterns},"facade.intensity":{kind:"number",description:"How strongly the windows show on the walls, and the landmarks' own texture among the buildings while their texture is detail, 0 (plain walls) to 1.",range:UNIT_RANGE},"facade.floorHeightMeters":{kind:"number",description:"Height of one storey, which spaces the rows of windows. The ground floor is a third taller.",range:{min:2.5,max:6,step:.1,bounds:"hard-min"}},"walls.color":{kind:"color",description:"Colour of the walls. Unset: the map style's 3D building colour of each kind of building, following the map colours that restyle them, and the colour of the buildings of no named kind is the one reported. Landmarks left unset among the buildings take it too."},"roofs.color":{kind:"color",description:"Colour of the roofs. Unset: a shade darker than the walls of each building, and the colour reported is the walls' one."},"windows.color":{kind:"color",description:"Colour of the window glass."},"reflections.intensity":{kind:"number",description:"How much the window glass mirrors the street, the facades across it and the sky, and catches the sun, 0 (matte) to 1. Glass curtain walls reflect the most, landmarks a little; the sky's colour is the ambient light's.",range:UNIT_RANGE},"litWindows.color":{kind:"color",description:"Colour of the windows lit from inside."},"litWindows.fraction":{kind:"number",description:"Share of the windows lit from inside, 0 to 1. The dark presets light some.",range:UNIT_RANGE},"litWindows.intensity":{kind:"number",description:"Brightness of the lit windows, 0 to 1. Pair it with the map effects bloom for a night glow.",range:UNIT_RANGE},"light.direction":{kind:"number",description:"Direction the light comes from, in degrees clockwise from north. Shadows fall the opposite way.",range:{min:0,max:359,step:1,bounds:"hard"}},"light.altitude":{kind:"number",description:"Height of the light above the horizon, in degrees (90 = overhead); lower casts longer shadows.",range:{min:5,max:90,step:1,bounds:"hard"}},"light.color":{kind:"color",description:"Colour of the light: the sun on light presets, the moon on dark ones."},"light.intensity":{kind:"number",description:"Strength of the light, 0 to 1.",range:UNIT_RANGE},"ambientLight.color":{kind:"color",description:"Colour of the light from the sky, which also tints the reflections in the glass."},"ambientLight.intensity":{kind:"number",description:"Strength of the light from the sky, 0 to 1, which lights the walls in shade.",range:UNIT_RANGE},"shadows.visible":{kind:"toggle",description:"Shadows the buildings and the landmarks among them cast, on each other and on the ground."},"shadows.intensity":{kind:"number",description:"Darkness of the shadows, 0 to 1.",range:UNIT_RANGE},"roadLabels.occluded":{kind:"toggle",description:"Road names draw under the buildings: hidden wherever a building covers them, they give way to the labels above them."},"pois.occluded":{kind:"toggle",description:"The style's POIs draw under the buildings: hidden wherever a building covers them, still keeping other labels off, they give way to the labels above them."}}),buildings3DKnobIds=/* @__PURE__ */buildings3DKnobCatalogue.map(({id:e})=>e),ZOOM_RANGE={min:0,max:22,step:1,bounds:"hard"},landmarkTextureUses=["mask","detail","color"],landmarks3DKnobCatalogue=/* @__PURE__ */withIds({visible:{kind:"toggle",description:"The landmark models.",default:!0},color:{kind:"color",description:"Colour the landmarks are shaded in. Unset: the base map's 3D buildings' colour, following the map colours that restyle them."},texture:{kind:"enum",description:"What the landmarks' textures add to their silhouette: mask (nothing), detail (their light and shade over the color) or color (their own colours, in place of the color). Unset: mask, or detail while a Buildings3D draws.",options:landmarkTextureUses},opacity:{kind:"number",description:"Opacity of the landmarks, 0 to 1. Unset: the base map's 3D buildings' opacity.",range:UNIT_RANGE},verticalGradient:{kind:"toggle",description:"Whether the landmarks' walls darken towards the ground. Unset: as the base map's 3D buildings do. No effect while a Buildings3D draws, whose walls have no gradient."},minZoom:{kind:"number",description:"Lowest zoom the landmarks are drawn at. Unset: the base map's 3D buildings' one.",range:ZOOM_RANGE},maxZoom:{kind:"number",description:"Highest whole zoom level the landmarks are drawn at, up to the next one. Unset: the base map's 3D buildings' one, or 22 while a Buildings3D draws.",range:ZOOM_RANGE}}),landmarks3DKnobIds=/* @__PURE__ */landmarks3DKnobCatalogue.map(({id:e})=>e),buildLandmarksTileURL=()=>{const{commonBaseURL:e,apiKey:t}=TomTomConfig.instance.get();return`${e}/maps/orbis/display/3d/landmarks/tile/{z}/{x}/{y}?${t?`key=${t}&`:""}apiVersion=2`},STREET_LIGHT_LOOK={visible:!0,color:"hsl(38, 6%, 90%)",texture:"mask",opacity:.7,verticalGradient:!0,minZoom:10,maxZoom:22},textureUseIndexOf=e=>landmarkTextureUses.indexOf(e),LANDMARK_TEXTURE_GLSL=/* @__PURE__ */(()=>`\nuniform int textureUse;\n${landmarkTextureUses.map((e,t)=>`const int TEXTURE_${e.toUpperCase()} = ${t};`).join("\n")}\nconst vec3 LANDMARK_LUMA = vec3(0.2126, 0.7152, 0.0722);\n\n\nvec3 landmarkTextureMean(sampler2D source, vec2 uv) {\nvec4 mean = textureLod(source, uv, 16.0);\nreturn mean.rgb / max(mean.a, 0.05);\n}\n\n\n\nfloat landmarkTextureDetail(vec4 texel, vec3 mean) {\nreturn clamp(dot(texel.rgb, LANDMARK_LUMA) / max(dot(mean, LANDMARK_LUMA), 1e-3), 0.3, 1.8);\n}\n`)(),VERTEX_SHADER="\nattribute float fillExtrusionGradient;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\n#ifdef USE_ALPHA_MASK\nvarying vec2 vUv;\n#endif\n\nvoid main() {\nvWorldNormal = normalize(mat3(modelMatrix) * normal);\nvGradient = fillExtrusionGradient;\n#ifdef USE_ALPHA_MASK\nvUv = uv;\n#endif\ngl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n",ALPHA_MASK_FRAGMENT_CHUNK="\n#ifdef USE_ALPHA_MASK\nuniform sampler2D landmarkMap;\nuniform float alphaMaskCutoff;\nvarying vec2 vUv;\n#endif\n",ALPHA_MASK_MAIN_CHUNK="\n#ifdef USE_ALPHA_MASK\nvec4 landmarkTexel = texture2D(landmarkMap, vUv);\nif (landmarkTexel.a < alphaMaskCutoff) {\ndiscard;\n}\n#endif\n",FRAGMENT_SHADER=/* @__PURE__ */(()=>`\nuniform vec3 diffuseColor;\nuniform vec3 lightPosition;\nuniform float lightIntensity;\nuniform vec3 lightColor;\nuniform float layerOpacity;\nuniform float verticalGradient;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\n${ALPHA_MASK_FRAGMENT_CHUNK}\n${LANDMARK_TEXTURE_GLSL}\n\nvoid main() {\n${ALPHA_MASK_MAIN_CHUNK}\nvec3 paint = diffuseColor;\nfloat colorValue = dot(diffuseColor, LANDMARK_LUMA);\n#ifdef USE_ALPHA_MASK\nif (textureUse != TEXTURE_MASK) {\nvec3 mean = landmarkTextureMean(landmarkMap, vUv);\nif (textureUse == TEXTURE_COLOR) {\npaint = sRGBTransferOETF(vec4(landmarkTexel.rgb, 1.0)).rgb;\ncolorValue = dot(sRGBTransferOETF(vec4(mean, 1.0)).rgb, LANDMARK_LUMA);\n} else {\npaint *= landmarkTextureDetail(landmarkTexel, mean);\n}\n}\n#endif\nvec3 normal = normalize(vWorldNormal);\n\n\nif (!gl_FrontFacing) {\nnormal = -normal;\n}\n\n\n\nvec3 flattened = vec3(normal.xy, 0.0);\nvec3 wallNormal = flattened / max(length(flattened), 1e-5);\nfloat upness = smoothstep(0.4, 0.8, normal.z);\nnormal = normalize(mix(wallNormal, vec3(0.0, 0.0, 1.0), upness));\nvec3 color = paint + vec3(0.03);\nfloat directional = clamp(dot(normal, lightPosition), 0.0, 1.0);\ndirectional = mix(1.0 - lightIntensity, max(1.0 - colorValue + lightIntensity, 1.0), directional);\nif (abs(normal.y) > 0.001) {\ndirectional *=\n(1.0 - verticalGradient) +\nverticalGradient * clamp(vGradient, mix(0.7, 0.98, 1.0 - lightIntensity), 1.0);\n}\nvec3 shaded = clamp(\ncolor * directional * lightColor,\nmix(vec3(0.0), vec3(0.3), vec3(1.0) - lightColor),\nvec3(1.0)\n);\ngl_FragColor = vec4(shaded, 1.0) * layerOpacity;\n}\n`)(),DEFAULT_LIGHT_POSITION=/* @__PURE__ */new Vector3(.2875,-.498,.996),parsedColor=/* @__PURE__ */new Color,srgbColor=/* @__PURE__ */new Color,FillExtrusionMaterial=class extends ShaderMaterial{constructor(e){super({uniforms:{diffuseColor:{value:new Vector3(1,1,1)},lightPosition:{value:DEFAULT_LIGHT_POSITION.clone()},lightIntensity:{value:.5},lightColor:{value:new Vector3(1,1,1)},layerOpacity:{value:1},verticalGradient:{value:1},textureUse:{value:textureUseIndexOf("mask")},...e&&{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}}},...e&&{defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:FRAGMENT_SHADER,side:e?DoubleSide:FrontSide,transparent:!0,blending:CustomBlending,blendSrc:OneFactor,blendDst:OneMinusSrcAlphaFactor})}copyShadingFrom(e){this.uniforms.diffuseColor.value.copy(e.uniforms.diffuseColor.value),this.uniforms.textureUse.value=e.uniforms.textureUse.value,this.uniforms.lightPosition.value.copy(e.uniforms.lightPosition.value),this.uniforms.lightIntensity.value=e.uniforms.lightIntensity.value,this.uniforms.lightColor.value.copy(e.uniforms.lightColor.value),this.uniforms.layerOpacity.value=e.uniforms.layerOpacity.value,this.uniforms.verticalGradient.value=e.uniforms.verticalGradient.value}setTextureUse(e){this.uniforms.textureUse.value=textureUseIndexOf(e)}setDiffuseColor(e){setCssColor(parsedColor,e).getRGB(srgbColor,SRGBColorSpace),this.uniforms.diffuseColor.value.set(srgbColor.r,srgbColor.g,srgbColor.b)}setLayerOpacity(e){this.uniforms.layerOpacity.value=e}setVerticalGradient(e){this.uniforms.verticalGradient.value=e?1:0}setLight(e,t,i,n){const a=Math.cos(t),o=Math.sin(t);this.uniforms.lightPosition.value.set(e.x*a-e.y*o,e.x*o+e.y*a,e.z),this.uniforms.lightIntensity.value=i,this.uniforms.lightColor.value.set(n.r,n.g,n.b)}},FillExtrusionDepthMaterial=class extends ShaderMaterial{constructor(e){super({...e&&{uniforms:{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}},defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:`\n${ALPHA_MASK_FRAGMENT_CHUNK}\nvoid main() {\n${ALPHA_MASK_MAIN_CHUNK}\ngl_FragColor = vec4(0.0);\n}\n`,side:e?DoubleSide:FrontSide,colorWrite:!1})}},FRAGMENT_DECLARATIONS=/* @__PURE__ */(()=>`\nuniform float detailIntensity;\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\n${GLASS_GLSL}\n${LANDMARK_TEXTURE_GLSL}\n\nconst float LANDMARK_REFLECTIVITY = 0.6;\n`)(),LandmarkFacadeMaterial=class extends MeshLambertMaterial{detailIntensity={value:1};textureUse={value:textureUseIndexOf("detail")};constructor(e,t){super({map:t?.map??null,alphaTest:t?.cutoff??0,side:t?DoubleSide:FrontSide}),this.onBeforeCompile=t=>{Object.assign(t.uniforms,e,{detailIntensity:this.detailIntensity,textureUse:this.textureUse}),t.vertexShader=t.vertexShader.replace("#include <common>","#include <common>\n\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\n").replace("#include <begin_vertex>","#include <begin_vertex>\n\nvLandmarkPosition = (modelMatrix * vec4(transformed, 1.0)).xyz;\nvLandmarkNormal = mat3(modelMatrix) * objectNormal;\n"),t.fragmentShader=t.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS}`).replace("#include <map_fragment>","\nfloat landmarkGlass = 0.5;\n#ifdef USE_MAP\nvec4 landmarkTexel = texture2D(map, vMapUv);\ndiffuseColor.a *= landmarkTexel.a;\nif (textureUse != TEXTURE_MASK) {\nfloat detail = landmarkTextureDetail(landmarkTexel, landmarkTextureMean(map, vMapUv));\ndiffuseColor.rgb = textureUse == TEXTURE_COLOR\n? landmarkTexel.rgb\n: diffuseColor.rgb * mix(1.0, detail, detailIntensity);\nlandmarkGlass = 1.0 - smoothstep(0.6, 1.2, detail);\n}\n#endif\nvec3 landmarkNormal = normalize(vLandmarkNormal) * (gl_FrontFacing ? 1.0 : -1.0);\nvec3 landmarkToEye = normalize(eyePosition - vLandmarkPosition);\nvec3 landmarkReflected = reflect(-landmarkToEye, landmarkNormal);\nfloat landmarkReflectance = reflectivity * LANDMARK_REFLECTIVITY * mix(0.3, 1.0, landmarkGlass)\n* (1.0 - smoothstep(0.5, 0.9, abs(landmarkNormal.z)))\n* glassFresnel(landmarkNormal, landmarkToEye);\nvec3 landmarkMirrored = mix(mirroredStreet(), mirroredSky(landmarkReflected), smoothstep(-0.05, 0.05, landmarkReflected.z));\ndiffuseColor.rgb *= 1.0 - landmarkReflectance;\nvec3 glassSunReflection = mirroredSun(landmarkReflected) * landmarkReflectance;\n").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += landmarkMirrored * landmarkReflectance;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setLook(e){setCssColor(this.color,e.color),this.textureUse.value=textureUseIndexOf(e.texture),this.detailIntensity.value=e.detailIntensity,setMaterialOpacity(this,e.opacity)}},CREASE_ANGLE_RADIANS=Math.PI/6,ModelsSource=class{type="models";id;minzoom;maxzoom;map;tiles;scene;loadedTiles=/* @__PURE__ */new Set;accessDenied=!1;sceneOrigin=null;onTileLoaded;ktx2Loader;transcoderReady;gltfLoader;specification;withCredentials;coveringTileKeys=/* @__PURE__ */new Set;constructor(e,t){this.id=e,this.minzoom=t.minzoom??0,this.maxzoom=t.maxzoom??22,this.tiles=t.tiles,this.specification=t,this.withCredentials=t.withCredentials??!1,this.scene=new Group,this.ktx2Loader=new KTX2Loader(new LoadingManager).setCrossOrigin("anonymous").setTranscoderPath(t.transcoderPath??""),this.gltfLoader=(new GLTFLoader).setKTX2Loader(this.ktx2Loader).setMeshoptDecoder(MeshoptDecoder)}onAdd(e,t){this.map=e,this.ktx2Loader.detectSupport(t)}updateTiles(){if(0===this.tiles.length)return;const e=this.coveringTiles();this.coveringTileKeys=new Set(e.map(e=>e.key));for(const t of e)this.loadTile(t);this.showCoveringTilesOnly()}showCoveringTilesOnly(){for(const e of this.scene.children)e.visible=this.coveringTileKeys.has(e.userData.key)}coveringTiles(){const e={tileSize:this.map._camera.transform.tileSize,minzoom:this.minzoom,maxzoom:this.maxzoom,terrain:this.map.terrain};return this.map.coveringTiles(e)}loadTile(e){if(this.loadedTiles.has(e.key))return;this.loadedTiles.add(e.key);const t=e.canonical.url(this.tiles,this.map.getPixelRatio(),this.specification.scheme);this.fetchTile(t).then(t=>{t&&(prepareTileMeshes(t),this.rebaseToSceneOrigin(t),t.userData={isTile:!0,key:e.key},t.visible=this.coveringTileKeys.has(e.key),this.scene.add(t),this.map.triggerRepaint(),this.onTileLoaded?.(t,e.key))}).catch(t=>{console.warn(`Problem with loading ${e.toString()}: ${t?.message??"unknown"}`)})}rebaseToSceneOrigin(e){const t=[];if(e.traverse(e=>{isMesh(e)&&t.push(e)}),0===t.length)return;const i=t[0].position,n={x:Math.round(i.x),y:Math.round(i.y)};if(this.sceneOrigin){if(Math.hypot(i.x-this.sceneOrigin.x,i.y-this.sceneOrigin.y)>1e5){const e=n.x-this.sceneOrigin.x,t=n.y-this.sceneOrigin.y;this.scene.traverse(i=>{isMesh(i)&&(i.position.x-=e,i.position.y-=t)}),this.sceneOrigin=n}}else this.sceneOrigin=n;for(const a of t)a.position.x-=this.sceneOrigin.x,a.position.y-=this.sceneOrigin.y}async fetchTile(e){const t=await fetch(e,this.withCredentials?{credentials:"include"}:void 0);if(204===t.status||404===t.status)return null;if(403===t.status&&"InvalidReferer"!==await(async e=>(await e.json().catch(()=>{}))?.detailedError?.code)(t))throw this.accessDenied=!0,new Error("tile request failed with 403: Orbis 3D Landmarks is in Private Preview (https://docs.tomtom.com/legal/private-preview), and the API key needs access to it: request it from TomTom Sales at https://www.tomtom.com/contact-sales/?source_app=docs-portal&source_product=map-display-api-3d");if(!t.ok)throw new Error(`tile request failed with ${t.status}`);const i=await t.arrayBuffer();this.transcoderReady??=(async e=>{if(void 0!==this.specification.transcoderPath)return;const{resolveBundledTranscoderUrl:t}=await(import("./bundledTranscoder-CUVU7Ihm.js"));e.setURLModifier(t)})(this.ktx2Loader.manager),await this.transcoderReady;const{scene:n}=await this.gltfLoader.parseAsync(i,LoaderUtils.extractUrlBase(e));return n}},prepareTileMeshes=e=>{e.traverse(e=>{if(!isMesh(e))return;const t=e.material;t.alphaTest=.1,t.side=DoubleSide,e.userData.originalMaterial=t,e.castShadow=!0,e.receiveShadow=!0,e.geometry=toCreasedNormals(e.geometry,CREASE_ANGLE_RADIANS),bakeGradientAttribute(e)})},bakeGradientAttribute=e=>{const t=e.geometry,i=t.getAttribute("position");t.computeBoundingBox();const n=t.boundingBox?.max.z??0,a=n>0?Math.sqrt(n/150)/n:0,o=new Float32Array(i.count);for(let r=0;r<i.count;r++)o[r]=i.getZ(r)*a;t.setAttribute("fillExtrusionGradient",new BufferAttribute(o,1))},alphaMaskOf=e=>{const t=e.userData.originalMaterial;return t?.map?{map:t.map,cutoff:t.alphaTest}:void 0},ModelsLayer=class{id;type="custom";renderingMode="3d";renderer;scene;camera;tiles;directionalLight=new DirectionalLight(16777215,.5);ambientLight=new AmbientLight(16777215,.1);map;source;minzoom=0;maxzoom=22;visible=!0;diffuseColor="#ffffff";fillExtrusionMaterial=new FillExtrusionMaterial;depthPrepassMaterial=new FillExtrusionDepthMaterial;maskedFillExtrusionMaterials=/* @__PURE__ */new Map;facadeMaterials=/* @__PURE__ */new Map;buildingsLight;glass;opacity=1;textureUse="mask";tilesMainMatrix=/* @__PURE__ */new Float64Array(16);tilesStale=!0;markTilesStale=()=>{this.tilesStale=!0};constructor(e,t){this.id=e.id,this.source=new ModelsSource(this.id,t),this.tiles=this.source.scene,this.updateProperties(e)}updateProperties(e){this.visible="none"!==e.layout?.visibility,this.diffuseColor=e.paint?.["models-base-color"]??"#ffffff",this.minzoom=e.minzoom??0,this.maxzoom=e.maxzoom??22}setDirectionalLight(e,t,i){this.directionalLight.position.setFromSphericalCoords(e,MathUtils.degToRad(t),MathUtils.degToRad(i))}onAdd(e,t){this.map=e,this.scene=new Scene,this.tiles=this.source.scene,this.camera=new Camera,this.setDirectionalLight(1.15,90,0),this.scene.add(this.directionalLight,this.ambientLight),this.scene.add(this.tiles),this.renderer=new WebGLRenderer({canvas:e.getCanvas(),context:t,antialias:!0}),this.renderer.autoClear=!1,this.source.onAdd(e,this.renderer),this.tilesStale=!0,e.off("data",this.markTilesStale),e.on("data",this.markTilesStale)}render(e,t){!this.buildingsLight&&this.prepareFrame(t.defaultProjectionData.mainMatrix)&&(this.tiles.parent!==this.scene&&this.scene.add(this.tiles),this.syncLighting(),this.alignCameraToMap(t),this.renderer.resetState(),this.needsTranslucentPrepass()&&(this.useMaterials("depth"),this.renderer.render(this.scene,this.camera)),this.applyMaterials(),this.renderer.render(this.scene,this.camera))}prepareForBuildings(e,t){if(this.buildingsLight&&this.map&&!this.source.accessDenied&&this.prepareFrame(e))return t!==this.glass&&(this.facadeMaterials.forEach(e=>e.dispose()),this.facadeMaterials.clear(),this.glass=t),this.applyMaterials(),{origin:this.sceneOrigin,translucent:this.opacity<1}}useMaterials(e){if("depth"!==e){this.applyMaterials();const t="color"===e;return void this.facadeMaterials.forEach(e=>{e.colorWrite=t,e.depthWrite=t})}this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.maskedFillExtrusionVariant(e)?.depth??this.depthPrepassMaterial)})}prepareFrame(e){const t=this.map._camera.transform.tileZoom,i=Math.max(this.minzoom,this.source.minzoom);return this.tiles.visible=this.visible&&t>=i&&t<=this.maxzoom,!!this.tiles.visible&&(this.updateTilesWhenStale(e),this.groundLandmarksOnTerrain(),!0)}updateTilesWhenStale(e){(this.tilesMainMatrix.some((t,i)=>t!==e[i])||this.tilesStale)&&(this.tilesMainMatrix.set(e),this.tilesStale=!1,this.source.updateTiles())}groundLandmarksOnTerrain(){for(const e of this.tiles.children)e.visible&&e.traverse(e=>{isMesh(e)&&this.groundMeshOnTerrain(e)})}groundMeshOnTerrain(e){const t=this.terrainSamplePoints(e);if(!t)return;let i=null;for(const n of t){const t=this.map.queryTerrainElevation(n);if(null===t)return void(e.position.z=0);(null===i||t<i)&&(i=t)}null!==i&&(e.position.z=i-.5)}terrainSamplePoints(e){let t=e.userData.terrainSamplePoints;if(!t){e.geometry.boundingBox||e.geometry.computeBoundingBox();const i=e.geometry.boundingBox;if(!i||i.isEmpty())return null;const n=e.position.x+this.sceneOrigin.x,a=e.position.y+this.sceneOrigin.y,o=(i.min.x+i.max.x)/2,r=(i.min.y+i.max.y)/2;t=[[o,r],[i.min.x,i.min.y],[i.min.x,i.max.y],[i.max.x,i.min.y],[i.max.x,i.max.y],[o,i.min.y],[o,i.max.y],[i.min.x,r],[i.max.x,r]].map(([e,t])=>mercatorMetresToLngLat(n+e,a+t)),e.userData.terrainSamplePoints=t}return t}alignCameraToMap(e){const t=localFrameMatrix(e.defaultProjectionData.mainMatrix,mercatorMetresToLngLat(this.sceneOrigin.x,this.sceneOrigin.y),{units:"mercatorMeters",centerLatitude:this.map.getCenter().lat});setCameraProjection(this.camera,t)}get sceneOrigin(){return this.source.sceneOrigin??{x:0,y:0}}needsTranslucentPrepass(){return this.fillExtrusionMaterial.uniforms.layerOpacity.value<1}setOpacity(e){this.opacity=e,this.forEachFillExtrusionMaterial(t=>t.setLayerOpacity(e))}setBuildingsLight(e){this.buildingsLight=e}setVerticalGradient(e){this.forEachFillExtrusionMaterial(t=>t.setVerticalGradient(e))}setTextureUse(e){this.textureUse=e,this.forEachFillExtrusionMaterial(t=>t.setTextureUse(e))}getMaterial(e){return this.maskedFillExtrusionVariant(e)?.color??this.fillExtrusionMaterial}maskedFillExtrusionVariant(e){const t=alphaMaskOf(e);if(!t)return null;let i=this.maskedFillExtrusionMaterials.get(t.map);return i||(i={color:new FillExtrusionMaterial(t),depth:new FillExtrusionDepthMaterial(t)},i.color.copyShadingFrom(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.set(t.map,i)),i}forEachFillExtrusionMaterial(e){e(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.forEach(t=>e(t.color))}syncLighting(){const e=this.map,t=e.style?.light,i=t?.properties,n=t?.getCartesianPosition?.();if(i&&n)try{const t=i.get("intensity");this.directionalLight.intensity=t*Math.PI,this.ambientLight.intensity=(1-t)*Math.PI;const a={x:-n[0],y:n[1],z:n[2]};this.directionalLight.position.set(a.x,a.y,a.z);const o="viewport"===i.get("anchor")?-(e._camera.transform.bearingInRadians??0):0,r=i.get("color");this.forEachFillExtrusionMaterial(e=>e.setLight(a,o,t,r))}catch{}}applyMaterials(){const{buildingsLight:e,glass:t}=this;if(e&&t){const i={color:this.diffuseColor,texture:this.textureUse,detailIntensity:e["facade.intensity"],opacity:this.opacity};return this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.facadeMaterialOf(e,t))}),void this.facadeMaterials.forEach(e=>e.setLook(i))}this.forEachFillExtrusionMaterial(e=>e.setDiffuseColor(this.diffuseColor)),this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.getMaterial(e))})}facadeMaterialOf(e,t){const i=alphaMaskOf(e),n=i?.map??null;let a=this.facadeMaterials.get(n);return a||(a=new LandmarkFacadeMaterial(t,i),this.facadeMaterials.set(n,a)),a}},NO_LANDMARK_FILTER_CLAUSE=["!",["coalesce",["get","has_landmark"],!1]],Landmarks3D=class{map;layerID="orbis-3d-landmarks";basemapBuildingLayerID="3D - Building";modelsLayer;config;renderedLook;constructor(e,{withCredentials:t,transcoderPath:i,...n}={}){this.map=e,this.config=n,restyleLandmarksOn.set(e,()=>this.render());const a={id:this.layerID,type:"models",source:this.layerID},o={type:"models",tiles:[buildLandmarksTileURL()],minzoom:15,maxzoom:15,withCredentials:t??isProxyCredentialsMode(),transcoderPath:i};this.modelsLayer=new ModelsLayer(a,o),landmarksOn.set(e,this.modelsLayer),this.render(),this.map.addCustomLayer(this.modelsLayer,{beforeLayerConfig:"poi"}),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{this.map.mapReady&&!sameLook(this.look(),this.renderedLook)&&this.render()}),whenMapReady(e,()=>this.install())}get layer(){return this.modelsLayer}getConfig(){return structuredClone(this.config)}applyConfig(e){this.config=e,this.render()}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_knobValue(e){return this.look()[e]}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}install(){this.excludeLandmarkBuildingsFromBasemap(),this.modelsLayer.source.onTileLoaded=()=>{this.look().opacity<1&&this.render()},this.render()}excludeLandmarkBuildingsFromBasemap(){LayerFilterComposer.for(this.map).setClause(this.basemapBuildingLayerID,"landmarks3d.buildings",NO_LANDMARK_FILTER_CLAUSE)}readBuildingsLook(){const e=buildings3DLookOn.get(this.map)?.();if(e)return{color:e["walls.color"],texture:"detail",opacity:e.opacity,verticalGradient:!1,minZoom:e.minZoom};const t=this.map.mapLibreMap,i=t.getLayer(this.basemapBuildingLayerID);if(!i)return{};const n=e=>t.getPaintProperty(this.basemapBuildingLayerID,e),a=groupColorsOfPaint(n("fill-extrusion-color"))?.at(-1),o=n("fill-extrusion-opacity"),r=n("fill-extrusion-vertical-gradient");return{...a&&{color:a},..."number"==typeof o&&{opacity:o},..."boolean"==typeof r&&{verticalGradient:r},...void 0!==i.minzoom&&{minZoom:i.minzoom},...void 0!==i.maxzoom&&{maxZoom:i.maxzoom}}}look(){const e=this.map.mapReady?this.readBuildingsLook():{};return((e,t)=>{const i={...STREET_LIGHT_LOOK,...t},n=t=>e[t]??i[t];return{visible:n("visible"),color:n("color"),texture:n("texture"),opacity:n("opacity"),verticalGradient:n("verticalGradient"),minZoom:n("minZoom"),maxZoom:n("maxZoom")}})(this.config,e)}render(){const e=this.look();this.renderedLook=e,this.modelsLayer.visible=e.visible,this.modelsLayer.minzoom=e.minZoom,this.modelsLayer.maxzoom=e.maxZoom,this.modelsLayer.diffuseColor=e.color,this.modelsLayer.setTextureUse(e.texture),this.modelsLayer.setOpacity(e.opacity),this.modelsLayer.setVerticalGradient(e.verticalGradient),this.modelsLayer.setBuildingsLight(buildings3DLookOn.get(this.map)?.()),this.map.mapReady&&this.map.mapLibreMap.triggerRepaint()}};export{Buildings3D,Landmarks3D,ModelsLayer,ModelsSource,buildLandmarksTileURL,buildings3DKnobCatalogue,buildings3DKnobIds,buildingsPresets,facadePatterns,landmarkTextureUses,landmarks3DKnobCatalogue,landmarks3DKnobIds};
1
+ import{_ as LIGHT_ALTITUDE_RANGE,c as SURFACE_ID_COUNT,d as landmarkTextureUses,i as isSurfaceSeason,l as standardStyleSurfaceTargets,o as STYLE_LAYER_IDS,r as DEFAULT_SURFACE_SEASON,s as SURFACE_IDS,t as glSurfacesKnobCatalogue,u as surfaceKinds}from"./surfacesKnobCatalogue-B2lRYedD.js";import{BASE_MAP_SOURCE_ID,CLICK_EVENT_STATES,HOVER_EVENT_STATES,LayerFilterComposer,MERCATOR_UNITS_PER_EPSG3857_METER,StylingFoundationsModule,TomTomMapError,configWithKnobs,configWithoutKnob,existingAnchorLayerID,getMapLight,isMapColorName,knobValueIn,localFrameMatrix,mapStyleLayerIDs,mentionsZoom,parseCssColor,runWhenMapIsReady,standardStyleIdOf,toTomTomMapRequestError,wrapZoomFreeParts}from"@tomtom-org/maps-sdk/map";import{MercatorCoordinate}from"maplibre-gl";import{AddEquation,AmbientLight,Box2,Box3,BufferAttribute,BufferGeometry,Camera,Color,CustomBlending,DataArrayTexture,DataTexture,DepthTexture,DirectionalLight,DoubleSide,FloatType,FramebufferTexture,FrontSide,Frustum,GLSL3,Group,HemisphereLight,IcosahedronGeometry,InstancedBufferGeometry,Int16BufferAttribute,InterleavedBuffer,InterleavedBufferAttribute,LessEqualCompare,LessEqualDepth,LinearFilter,LinearMipmapLinearFilter,LoaderUtils,LoadingManager,MathUtils,Matrix3,Matrix4,Mesh,MeshBasicMaterial,MeshLambertMaterial,MinEquation,NearestFilter,OneFactor,OneMinusSrcAlphaFactor,PCFShadowMap,PlaneGeometry,Points,RGBAFormat,RGBFormat,RawShaderMaterial,Ray,Raycaster,RedFormat,RepeatWrapping,SRGBColorSpace,Scene,ShaderMaterial,ShadowMaterial,ShapeUtils,SrcAlphaFactor,Texture,UnsignedByteType,Vector2,Vector3,Vector4,WebGLRenderTarget,WebGLRenderer}from"three";import{TomTomConfig,isProxyCredentialsMode,pointInsidePolygon}from"@tomtom-org/maps-sdk/core";import{MeshoptDecoder}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{GLTFLoader}from"three/examples/jsm/loaders/GLTFLoader.js";import{KTX2Loader}from"three/examples/jsm/loaders/KTX2Loader.js";import{mergeVertices,toCreasedNormals}from"three/examples/jsm/utils/BufferGeometryUtils.js";var noSunShadow,THEMED_LIGHTS_light_direction=215,THEMED_LIGHTS_light_altitude=30,THEMED_LIGHTS_dark_direction=135,THEMED_LIGHTS_dark_altitude=35,THEMED_SUN_COLORS={light:"#fff3e0",dark:"#a9bde0"},SATELLITE_LIGHT={direction:THEMED_LIGHTS_light_direction,altitude:35},groundElevationAt=(e,t)=>e.terrain?e.queryTerrainElevation(t)??0:0,lightKnobsOf=e=>({"light.direction":e.direction,"light.altitude":Math.max(LIGHT_ALTITUDE_RANGE.min,e.altitude)}),towardsLightOf=(e,t)=>{const o=MathUtils.degToRad(e),r=MathUtils.degToRad(t);return[Math.sin(o)*Math.cos(r),Math.cos(o)*Math.cos(r),Math.sin(r)]},renderers=/* @__PURE__ */new WeakMap,rendererOf=(e,t)=>{let o=renderers.get(t);return o||(o=new WebGLRenderer({canvas:e.getCanvas(),context:t,antialias:!0}),o.autoClear=!1,drawShadowsOverWholeDepth(o,t),renderers.set(t,o)),o},fadeInFrom=(e,t,o)=>MathUtils.clamp((e-t)/o,0,1),metersPerMercatorAt=e=>Math.cos(MathUtils.degToRad(e))/MERCATOR_UNITS_PER_EPSG3857_METER,resetRendererFor=(e,t)=>{e.resetState(),e.setViewport(0,0,t.drawingBufferWidth,t.drawingBufferHeight)},drawShadowsOverWholeDepth=(e,t)=>{const o=e.shadowMap,r=o.render.bind(o);o.render=(...e)=>{if(!o.enabled||!o.autoUpdate&&!o.needsUpdate)return r(...e);const[a,i]=t.getParameter(t.DEPTH_RANGE);t.depthRange(0,1),r(...e),t.depthRange(a,i)}},isMesh=e=>!0===e.isMesh,parsedCssColors=/* @__PURE__ */new Map,parsedCssColor=e=>{if(parsedCssColors.has(e))return parsedCssColors.get(e);parsedCssColors.size>=64&&parsedCssColors.clear();const t=parseCssColor(e);return parsedCssColors.set(e,t),t},setCssColor=(e,t)=>{const o=parsedCssColor(t);return o?e.setRGB(o[0],o[1],o[2],SRGBColorSpace):e},sameJSON=(e,t)=>void 0!==t&&JSON.stringify(e)===JSON.stringify(t),setMaterialOpacity=(e,t)=>{e.opacity=t;const o=t<1;o!==e.transparent&&(e.transparent=o,e.needsUpdate=!0)},mercatorMetresToLngLat=(e,t)=>new MercatorCoordinate(.5+e*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t*MERCATOR_UNITS_PER_EPSG3857_METER).toLngLat().toArray(),setCameraProjection=(e,t)=>{e.projectionMatrix.fromArray(t),e.projectionMatrixInverse.copy(e.projectionMatrix).invert()},STOPS_OPERATORS=/* @__PURE__ */new Set(["interpolate","interpolate-hcl","interpolate-lab","step"]),colorWhere=(e,t,o)=>{if("string"==typeof e)return e;if(!Array.isArray(e))return;const[r,...a]=e;if(STOPS_OPERATORS.has(r))return colorWhere(a.at(-1),t,o);if("match"!==r||!((e,t)=>Array.isArray(e)&&2===e.length&&"get"===e[0]&&e[1]===t)(a[0],t))return;const i=a.slice(1,-1);for(let s=0;s<i.length;s+=2){const e=i[s];if(e===o||Array.isArray(e)&&e.includes(o))return colorWhere(i[s+1],t,o)}return colorWhere(a.at(-1),t,o)},BUILDING_GROUPS=["education","transport","leisure","healthcare","shopping"],oneColorForEveryGroup=e=>new Array(BUILDING_GROUPS.length+1).fill(e),groupColorsOfPaint=e=>{const t=(e=>{if(!Array.isArray(e)||"interpolate"!==e[0]||0!==e[3])return e;const[t,o,r]=Array.isArray(e[4])?e[4]:[],a=Array.isArray(o)&&"feature-state"===o[0]&&"color"===o[1];return"to-color"===t&&a?r:e})(e);if("string"==typeof t)return oneColorForEveryGroup(t);if(!Array.isArray(t)||"match"!==t[0])return;const o=t.at(-1);return"string"==typeof o?[...BUILDING_GROUPS.map(e=>colorWhere(t,"group",e)??o),o]:void 0},landmarksOn=/* @__PURE__ */new WeakMap,buildings3DLookOn=/* @__PURE__ */new WeakMap,restyleLandmarksOn=/* @__PURE__ */new WeakMap,buildingsPickOn=/* @__PURE__ */new WeakMap,KnobConfigured=class{config;constructor(e){this.config={...e}}getConfig(){return structuredClone(this.config)}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}lookValue(e,t){const o=e[t];return"light.direction"===t?(r=o,(Math.round(r)%360+360)%360):o;var r}},resolvePalette=(e,t)=>e.flatMap(e=>{if(!e.startsWith("colors."))return parsedCssColor(e)?[e]:[];const o=e.slice(7),r=isMapColorName(o)?t[o]:void 0;return r?[r]:[]}).slice(0,8),publishMapColorsFor=(e,t,o)=>o||!(e=>e.some(e=>e.startsWith("colors.")))(t)?o:stylingModuleOf(e),stylingModuleOf=e=>StylingFoundationsModule.get(e).catch(()=>{}),createPaletteUniforms=()=>({paletteColors:{value:Array.from({length:8},()=>new Vector3)},paletteCount:{value:0},paletteBlend:{value:0},paletteIntensity:{value:1},colorVariation:{value:0}}),parsedColor$1=/* @__PURE__ */new Color,setPaletteChoice=(e,t,o)=>{t.colors.forEach((t,r)=>{setCssColor(parsedColor$1,t),"srgb"===o&&parsedColor$1.getRGB(parsedColor$1,SRGBColorSpace),e.colors.value[r].set(parsedColor$1.r,parsedColor$1.g,parsedColor$1.b)}),e.count.value=t.colors.length,e.blend.value="blend"===t.mode?1:0,e.intensity.value=t.intensity},setPaletteUniforms=(e,t,o)=>{setPaletteChoice({colors:e.paletteColors,count:e.paletteCount,blend:e.paletteBlend,intensity:e.paletteIntensity},t,o),e.colorVariation.value=t.variation},PALETTE_GLSL=/* @__PURE__ */(()=>"\nuniform vec3 paletteColors[8];\nuniform float paletteCount;\nuniform float paletteBlend;\nuniform float paletteIntensity;\nuniform float colorVariation;\n\n\nfloat facadeHash(vec3 point){\npoint=fract(point*.1031);\npoint+=dot(point,point.zyx+31.32);\nreturn fract((point.x+point.y)*point.z);\n}\n\nvec3 paletteColorAt(vec3 colors[8],float count,float blend,float at){\nint last=int(count)-1;\nif(blend<.5)return colors[min(int(at*count),last)];\n\nfloat position=at*float(last);\nint index=int(position);\nreturn mix(colors[index],colors[min(index+1,last)],fract(position));\n}\n\nvec3 variedColor(vec3 color,float id,float shade){\nif(paletteCount>.5){\nvec3 taken=paletteColorAt(paletteColors,paletteCount,paletteBlend,facadeHash(vec3(id,17.,3.)));\ncolor=mix(color,taken,paletteIntensity);\n}\nfloat warmth=facadeHash(vec3(id,29.,7.))-.5;\nreturn color*(1.+colorVariation*(shade-.5))\n*(vec3(1.)+colorVariation*.15*warmth*vec3(1.,0.,-1.));\n}\n")(),isHover=e=>HOVER_EVENT_STATES.includes(e),isClick=e=>CLICK_EVENT_STATES.includes(e),tableOf=(e,t)=>{const o=new Uint8Array(2048*e*4);t&&o.set(t.image.data);const r=new DataTexture(o,2048,e,RGBAFormat);return r.magFilter=NearestFilter,r.minFilter=NearestFilter,r.needsUpdate=!0,r},ObjectHighlights=class{uniforms={objectColors:{value:tableOf(1)},hoveredObject:{value:-1},clickedObject:{value:-1},hoverHighlight:{value:new Vector4},clickHighlight:{value:new Vector4}};indices=/* @__PURE__ */new Map;objects=[];states=/* @__PURE__ */new Map;colors={};indexOf(e,t={}){const o=String(e);let r=this.indices.get(o);return void 0===r?(r=this.objects.length,this.indices.set(o,r),this.objects.push({id:e,properties:t}),this.growTable()):this.objects[r]={id:e,properties:t},r}objectAt(e){return this.objects[e]}setColors(e){for(const t of Object.keys(this.colors))this.writeColor(t,void 0);this.colors={...e};for(const[t,o]of Object.entries(e))this.writeColor(t,o);this.table.needsUpdate=!0}getColors(){return{...this.colors}}setLook(e){const t=(t,o)=>{const r=parsedCssColor(e[`${t}.color`]);o.set(r?.[0]??0,r?.[1]??0,r?.[2]??0,r?e[`${t}.intensity`]:0)};t("hover",this.uniforms.hoverHighlight.value),t("click",this.uniforms.clickHighlight.value)}setState(e,t){const o=String(e);t?this.states.set(o,t):this.states.delete(o);let r=-1,a=-1;for(const[i,s]of this.states)isHover(s)?r=this.indexOfKey(i):isClick(s)&&(a=this.indexOfKey(i));this.uniforms.hoveredObject.value=r,this.uniforms.clickedObject.value=a}get table(){return this.uniforms.objectColors.value}indexOfKey(e){return this.indices.get(e)??this.indexOf(e)}writeColor(e,t){const o=4*this.indexOfKey(e),r=this.table.image.data,a=void 0===t?void 0:parsedCssColor(t);a?r.set([a[0],a[1],a[2],1].map(e=>Math.round(255*e)),o):r[o+3]=0}growTable(){const e=this.table.image.height;if(this.objects.length<=2048*e)return;const t=this.table;this.uniforms.objectColors.value=tableOf(2*e,t),t.dispose()}},highlightGlsl=e=>`\nuniform sampler2D objectColors;\nuniform float hoveredObject;\nuniform float clickedObject;\nuniform vec4 hoverHighlight;\nuniform vec4 clickHighlight;\n\nvec3 inMaterialSpace(vec3 color){\n${"linear"===e?"return sRGBTransferEOTF(vec4(color, 1.0)).rgb;":"return color;"}\n}\n\n\nvec4 ownColorOf(float object){\nif(object<-.5)return vec4(0.);\nint width=textureSize(objectColors,0).x;\nint index=int(object+.5);\nreturn texelFetch(objectColors,ivec2(index%width,index/width),0);\n}\n\nbool hasOwnColor(float object){\nreturn ownColorOf(object).a>.5;\n}\n\nvec3 ownColor(vec3 color,float object){\nvec4 own=ownColorOf(object);\nreturn mix(color,inMaterialSpace(own.rgb),own.a);\n}\n\nvec3 stateColor(vec3 color,float object){\nif(object<-.5)return color;\nif(abs(object-clickedObject)<.5)return mix(color,inMaterialSpace(clickHighlight.rgb),clickHighlight.a);\nif(abs(object-hoveredObject)<.5)return mix(color,inMaterialSpace(hoverHighlight.rgb),hoverHighlight.a);\nreturn color;\n}\n\nvec3 highlighted(vec3 color,float object){\nreturn stateColor(ownColor(color,object),object);\n}\n`,rayThrough=(e,t,o)=>{const r=t.x/o.clientWidth*2-1,a=1-t.y/o.clientHeight*2,i=new Vector3(r,a,-1).applyMatrix4(e.projectionMatrixInverse),s=new Vector3(r,a,1).applyMatrix4(e.projectionMatrixInverse);return new Ray(i,s.sub(i).normalize())},isShown=e=>{for(let t=e;t;t=t.parent)if(!t.visible)return!1;return!0},nearestTriangleOf=(e,t,o,r)=>{const a=o.geometry.getAttribute("position"),[i,s,n,l]=[new Vector3,new Vector3,new Vector3,new Vector3];let c;for(let d=r.start;d<r.end;d+=3){if(i.fromBufferAttribute(a,d),s.fromBufferAttribute(a,d+1),n.fromBufferAttribute(a,d+2),!t.intersectTriangle(i,s,n,!1,l))continue;const r=l.applyMatrix4(o.matrixWorld).distanceTo(e.origin);(void 0===c||r<c)&&(c=r)}return c},piecesAlong=(e,t,o,r)=>{const a=o.geometry.boundingSphere;if(a&&!t.intersectsSphere(a))return[];const i=new Vector3,s=[];for(const n of r){if(!t.intersectBox(n.box,i))continue;const r=n.box.containsPoint(t.origin)?0:i.applyMatrix4(o.matrixWorld).distanceTo(e.origin);s.push({piece:n,distance:r})}return s.sort((e,t)=>e.distance-t.distance)},raycaster=/* @__PURE__ */new Raycaster,nearestLandmark=(e,t,o=Number.POSITIVE_INFINITY)=>{raycaster.ray.copy(e),raycaster.far=o;for(const{object:r,distance:a}of raycaster.intersectObject(t,!0))if(isMesh(r)&&isShown(r))return{landmark:r,distance:a}},renderedTilesOf=(e,t)=>{const o=e.style?.tileManagers[t];return(o?.getRenderableIds()??[]).flatMap(e=>o?.getTileByID(e)??[])},tileBoundsOf=({canonical:e,wrap:t})=>{const o=2**-e.z;return{corner:[t+e.x*o,e.y*o],size:o}},shadowMaps=/* @__PURE__ */new WeakMap,setSunShadowMap=(e,t)=>{t?shadowMaps.set(e,t):shadowMaps.delete(e)},DAY={opacity:1,minZoom:15,"walls.palette":[],"walls.paletteMode":"pick","walls.paletteIntensity":1,"walls.variation":.12,"roofs.palette":[],"roofs.paletteMode":"pick","roofs.paletteIntensity":1,"hover.intensity":.35,"click.intensity":.7,"facade.pattern":"mixed","facade.intensity":.85,"facade.floorHeightMeters":3.4,"windows.color":"#8da3b6","reflections.intensity":.7,"litWindows.color":"#ffd08a","litWindows.fraction":0,"litWindows.intensity":.8,"light.direction":THEMED_LIGHTS_light_direction,"light.altitude":THEMED_LIGHTS_light_altitude,"light.color":THEMED_SUN_COLORS.light,"light.intensity":.75,"ambientLight.color":"#dce8f5","ambientLight.intensity":.45,"shadows.visible":!0,"shadows.intensity":.7,"roadLabels.occluded":!1,"pois.occluded":!1},NIGHT=/* @__PURE__ */(()=>({...DAY,"facade.intensity":.9,"windows.color":"#1a2330","litWindows.color":"#f2c98f","litWindows.fraction":.3,"litWindows.intensity":.35,"light.direction":THEMED_LIGHTS_dark_direction,"light.altitude":THEMED_LIGHTS_dark_altitude,"light.color":THEMED_SUN_COLORS.dark,"light.intensity":.3,"ambientLight.color":"#5a6c94","ambientLight.intensity":.5,"shadows.intensity":.4}))(),PRESETS=/* @__PURE__ */(()=>({streetLight:DAY,streetDark:NIGHT,streetLightDriving:{...DAY,"facade.intensity":.55,"shadows.intensity":.5},streetDarkDriving:{...NIGHT,"facade.intensity":.7,"litWindows.fraction":.2},monoLight:{...DAY,"facade.intensity":.6,"windows.color":"#b4b9bf","light.color":"#ffffff","ambientLight.color":"#f2f4f7","ambientLight.intensity":.55,"shadows.intensity":.5},monoDark:{...NIGHT,"facade.intensity":.75,"windows.color":"#1f2226","litWindows.color":"#d3dae4","litWindows.fraction":.2,"litWindows.intensity":.3,"light.color":"#c7d0de","ambientLight.color":"#565d68"},streetSatellite:{...DAY,"facade.intensity":1,"walls.color":"#d8d0c2","roofs.color":"#8f8a82","windows.color":"#647b90","light.color":"#fff0d4","light.intensity":.8,"light.direction":SATELLITE_LIGHT.direction,"light.altitude":SATELLITE_LIGHT.altitude,"shadows.intensity":.75}}))(),presetOf=(e,t)=>{const o=e.preset??"auto";return PRESETS["auto"===o?t:o]},towardsSun=(e,t=new Vector3)=>t.set(...towardsLightOf(e["light.direction"],e["light.altitude"])),resolveBuildingsSun=(e,t,o)=>{const r=presetOf(e,t),a=o?lightKnobsOf(o):{},i=t=>knobValueIn(e,t)??a[t]??r[t];return{"light.direction":i("light.direction"),"light.altitude":i("light.altitude")}},isDrawn=(e,t)=>!0!==e.underground&&!0!==e.has_part&&!1!==e.extrude&&!(t.withoutLandmarks&&!0===e.has_landmark),numberOr=(e,t)=>"number"==typeof e?e:t,seedOf=e=>{let t=2166136261;for(const o of String(e))t=Math.imul(t^(o.codePointAt(0)??0),16777619);return(t>>>0)/2**32},isInside=(e,{x:t,y:o})=>{let r=!1;for(const a of e)for(let e=0,i=a.length-1;e<a.length;i=e++){const[s,n]=[a[i],a[e]];s.y>o!=n.y>o&&t<(n.x-s.x)*(o-s.y)/(n.y-s.y)+s.x&&(r=!r)}return r},outlineAround=(e,t)=>{const[o,r]=pointInsidePolygon(t.map(e=>e.map(e=>[e.x,e.y]))),a=new Vector2(o,r);let i;for(const s of e)(void 0===i||s.area<i.area)&&s.box.containsPoint(a)&&isInside(s.rings,a)&&(i=s);return i},GROUP_INDEX=/* @__PURE__ */(()=>new Map(BUILDING_GROUPS.map((e,t)=>[e,t])))(),readBuildings=(e,t,o)=>{const r=e.latestFeatureIndex?.loadVTLayers()[t];if(!r?.length)return{footprints:[],extent:4096};const{canonical:a}=e.tileID,i=Array.from({length:r.length},(e,t)=>r.feature(t)).filter(e=>3===e.type),s=i.flatMap(e=>{if(!0!==e.properties.has_part||void 0===e.id)return[];const t=e.loadGeometry(),o=(new Box2).setFromPoints(t.flat()),r=Math.abs(t.reduce((e,t)=>e+ShapeUtils.area(t),0));return[{id:e.id,rings:t,box:o,area:r,properties:e.properties}]}),n=[];for(const l of i){if(!isDrawn(l.properties,o))continue;const e=l.loadGeometry(),t=!0===l.properties.part&&s.length?outlineAround(s,e):void 0,r=t?.id??l.id??`${a.z}/${a.x}/${a.y}:${e[0]?.[0]?.x},${e[0]?.[0]?.y}`;n.push({rings:e,base:numberOr(l.properties.ground_height,0),height:numberOr(l.properties.height,4),group:GROUP_INDEX.get(l.properties.group)??BUILDING_GROUPS.length,seed:seedOf(r),id:r,properties:t?.properties??l.properties})}return{footprints:n,extent:r.extent??r.feature(0).extent}},groundUnder=(e,t)=>{const{groundAt:o}=t;if(!o||!e.length)return 0;const r=e.map(({x:e})=>e),a=e.map(({y:e})=>e),[i,s,n,l]=[Math.min(...r),Math.max(...r),Math.min(...a),Math.max(...a)];return Math.min(...[{x:i,y:n},{x:s,y:n},{x:s,y:l},{x:i,y:l}].map(o))-.5},FACADE_ATTRIBUTES={uv:"facadeUv",frame:"facadeFrame",kind:"facadeKind"},ROOF_NORMAL=[0,0,1],isBorderEdge=(e,t,o)=>e.x<=0&&t.x<=0||e.x>=o&&t.x>=o||e.y<=0&&t.y<=0||e.y>=o&&t.y>=o,runsOutsideTile=(e,t,o)=>0===e&&(t<0||o-t<0),enteringAt=(e,t)=>e<0?t/e:0,leavingAt=(e,t)=>e<=0?1:t/e,insideTile=(e,t,o)=>{const r=t.x-e.x,a=t.y-e.y;if(runsOutsideTile(r,e.x,o)||runsOutsideTile(a,e.y,o))return;const i=Math.max(0,enteringAt(-r,e.x),enteringAt(r,o-e.x),enteringAt(-a,e.y),enteringAt(a,o-e.y)),s=Math.min(1,leavingAt(-r,e.x),leavingAt(r,o-e.x),leavingAt(-a,e.y),leavingAt(a,o-e.y));return i<s?[i,s]:void 0},GeometryWriter=class{attributeSizes=[["position",3],["normal",3],[FACADE_ATTRIBUTES.uv,2],[FACADE_ATTRIBUTES.frame,4],[FACADE_ATTRIBUTES.kind,2],["highlightIndex",1]];count=0;capacity=4096;arrays=this.allocate();normal=ROOF_NORMAL;frame=[0,0,0,0];roof=0;group=0;object=0;startBuilding(e){this.object=e}boxOf(e,t){const o=new Box3,r=new Vector3;for(let a=e;a<t;a++)o.expandByPoint(r.fromArray(this.arrays.position,3*a));return o}startSurface(e,t,o,r){this.normal=e,this.frame=t,this.roof=o,this.group=r}vertex(e,t,o,r,a){if(this.count===this.capacity){this.capacity*=2;const e=this.arrays;this.arrays=this.allocate();for(const[t]of this.attributeSizes)this.arrays[t].set(e[t])}const i=this.count++,{normal:s,frame:n,roof:l,group:c}=this,{position:d,normal:u,[FACADE_ATTRIBUTES.uv]:f}=this.arrays,h=this.arrays[FACADE_ATTRIBUTES.frame],m=this.arrays[FACADE_ATTRIBUTES.kind];d[3*i]=e,d[3*i+1]=t,d[3*i+2]=o,u[3*i]=s[0],u[3*i+1]=s[1],u[3*i+2]=s[2],f[2*i]=r,f[2*i+1]=a,h[4*i]=n[0],h[4*i+1]=n[1],h[4*i+2]=n[2],h[4*i+3]=n[3],m[2*i]=l,m[2*i+1]=c,this.arrays.highlightIndex[i]=this.object}toGeometry(){const e=new BufferGeometry;for(const[t,o]of this.attributeSizes)e.setAttribute(t,new BufferAttribute(this.arrays[t].slice(0,this.count*o),o));return e.computeBoundingSphere(),e}allocate(){return Object.fromEntries(this.attributeSizes.map(([e,t])=>[e,new Float32Array(this.capacity*t)]))}},writeWalls=(e,t,o,r,a,i)=>{const{base:s,height:n,seed:l,group:c}=r,d=o.length-1,u=o[0].equals(o[d])?d:o.length;for(let f=0;f<u;f++){const r=(f+1)%o.length;if(isBorderEdge(t[f],t[r],a))continue;const d=insideTile(t[f],t[r],a);if(!d)continue;const u=o[f],h=o[r],m=u.distanceTo(h);if(0===m)continue;const p=h.x-u.x,g=h.y-u.y,v=[g/m,-p/m,0],[_,w]=d,y=_>0||w<1,x=y?(u.x*p+u.y*g)/m:0;e.startSurface(v,[y?0:m,s,n,l],0,c);const b=(t,o)=>e.vertex(u.x+p*t,u.y+g*t,i+o,x+t*m,o);b(_,s),b(w,s),b(w,n),b(_,s),b(w,n),b(_,n)}},clipToTile=(e,t)=>{const o=[e=>e.x,e=>t-e.x,e=>e.y,e=>t-e.y];let r=e;for(const a of o){const e=r;r=[],e.forEach((t,o)=>{const i=e[(o||e.length)-1],s=a(t),n=a(i);if(s>=0!=n>=0){const e=n/(n-s);r.push({x:i.x+(t.x-i.x)*e,y:i.y+(t.y-i.y)*e})}s>=0&&r.push(t)})}return r},writeRoof=(e,t,o,r,a)=>{if(t.length<3)return;const i=ShapeUtils.triangulateShape(t,o),s=[t,...o].flat(),{height:n,group:l}=r;e.startSurface(ROOF_NORMAL,[0,r.base,n,r.seed],1,l);const c=t=>e.vertex(t.x,t.y,a+n,t.x,t.y);for(const[d,u,f]of i){const e=s[d],t=s[u],o=s[f],r=(t.x-e.x)*(o.y-e.y)-(t.y-e.y)*(o.x-e.x)>0;c(e),c(r?t:o),c(r?o:t)}},writeBuilding=(e,t,o)=>{if(t.height<=t.base)return;const r=e=>new Vector2(o.originX+e.x*o.metresPerUnit,o.originY-e.y*o.metresPerUnit);for(const[a,...i]of(e=>{const t=[];let o;for(const r of e){const e=ShapeUtils.area(r);0!==e&&(o??=e<0,o===e<0?t.push([r]):t.at(-1)?.push(r))}return t})(t.rings)){const s=(e,t)=>{const o=e.map(r);return ShapeUtils.area(o)>0!==t?{tileRing:[...e].reverse(),sceneRing:[...o].reverse()}:{tileRing:e,sceneRing:o}},n=s(a,!0),l=i.map(e=>s(e,!1)),c=groundUnder(a,o);for(const r of[n,...l])writeWalls(e,r.tileRing,r.sceneRing,t,o.extent,c);const d=e=>clipToTile(e,o.extent).map(r),u=i.map(d).filter(e=>e.length>=3);writeRoof(e,d(a),u,t,c)}},BuildingsExtrusion=class{buildings;frame;indexOf;pieces=[];writer=new GeometryWriter;next=0;constructor(e,t,o){this.buildings=e,this.frame=t,this.indexOf=o}extrudeUntil(e){do{if(this.next===this.buildings.length)break;const e=this.buildings[this.next++],t=this.indexOf(e),o=this.writer.count;this.writer.startBuilding(t),writeBuilding(this.writer,e,this.frame);const r=this.writer.count;r>o&&this.pieces.push({index:t,start:o,end:r,box:this.writer.boxOf(o,r)})}while(performance.now()<e);return this.next===this.buildings.length}toGeometry(){return this.writer.toGeometry()}},GLASS_GLSL="\nuniform vec3 eyePosition;\nuniform vec3 sunDirection;\nuniform vec3 sunColor;\nuniform vec3 skyColor;\nuniform float skyIntensity;\nuniform float reflectivity;\nconst float SKY_GLOW=.5;\nconst float SUN_GLOW=.6;\n\n\n\nvec3 mirroredSky(vec3 direction){\nvec2 heading=normalize(direction.xy+1e-4);\nvec3 sky=skyColor*skyIntensity*mix(3.,1.8,smoothstep(0.,.7,direction.z));\nfloat sunSide=max(dot(heading,normalize(sunDirection.xy+1e-4)),0.);\nreturn sky+sunColor*SKY_GLOW*sunSide*sunSide*(1.-smoothstep(0.,.6,direction.z))*(1.-sunDirection.z);\n}\n\n\nvec3 mirroredStreet(){\nreturn(skyColor*skyIntensity+sunColor*sunDirection.z*smoothstep(.35,.75,sunDirection.z))*.25;\n}\n\n\nvec3 mirroredSun(vec3 reflected){\nreturn sunColor*pow(max(dot(reflected,sunDirection),0.),12.)*SUN_GLOW;\n}\n\n\nfloat glassFresnel(vec3 normal,vec3 toEye){\nreturn .25+.75*pow(1.-clamp(dot(normal,toEye),0.,1.),5.);\n}\n",SUN_IN_THE_GLASS="\n#if NUM_DIR_LIGHTS > 0\nvec3 glassSunSeen=directLight.color/max(directionalLights[0].color,vec3(1e-4));\ntotalEmissiveRadiance+=glassSunReflection*clamp(max(glassSunSeen.r,max(glassSunSeen.g,glassSunSeen.b)),0.,1.);\n#endif\n",WINDOW_LAYOUTS=[{across:[.29,.71],up:[.3,.78]},{across:[.1,.9],up:[.22,.8]},{across:[.05,.95],up:[.04,.95]},{across:[.06,.94],up:[.09,.85]}],coverage=(e,[t,o])=>Math.max(0,Math.min(e+1,128*o)-Math.max(e,128*t)),createWindowProfiles=()=>{const e=new Uint8Array(128*WINDOW_LAYOUTS.length*2);WINDOW_LAYOUTS.flatMap(({across:e,up:t})=>[e,t]).forEach((t,o)=>{for(let r=0;r<128;r++)e[128*o+r]=Math.round(255*coverage(r,t))});const t=new DataArrayTexture(e,128,1,2*WINDOW_LAYOUTS.length);return t.format=RedFormat,t.type=UnsignedByteType,t.wrapS=RepeatWrapping,t.magFilter=LinearFilter,t.minFilter=LinearMipmapLinearFilter,t.generateMipmaps=!0,t.needsUpdate=!0,t},GROUP_COLOR_COUNT=/* @__PURE__ */(()=>BUILDING_GROUPS.length+1)(),PATTERN_INDEX={plain:0,residential:1,office:2,glass:3,mixed:4},VERTEX_DECLARATIONS$1=/* @__PURE__ */(()=>`\nattribute vec2 ${FACADE_ATTRIBUTES.uv};\nattribute vec4 ${FACADE_ATTRIBUTES.frame};\nattribute vec2 ${FACADE_ATTRIBUTES.kind};\nattribute float highlightIndex;\nvarying float vHighlightIndex;\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n`)(),VERTEX_ASSIGNMENTS$1=/* @__PURE__ */(()=>`\nvFacadeUv= ${FACADE_ATTRIBUTES.uv};\nvFacadeFrame= ${FACADE_ATTRIBUTES.frame};\nvFacadeKind= ${FACADE_ATTRIBUTES.kind};\nvHighlightIndex= highlightIndex;\nvScenePosition=(modelMatrix*vec4(transformed,1.)).xyz;\nvSceneNormal=normalize(mat3(modelMatrix)*objectNormal);\n`)(),FRAGMENT_DECLARATIONS$1=/* @__PURE__ */(()=>`\nuniform vec3 wallColors[${GROUP_COLOR_COUNT}];\nuniform vec3 roofColor;\nuniform float roofFollowsWalls;\nuniform float roofColorSet;\nuniform vec3 roofPaletteColors[8];\nuniform float roofPaletteCount;\nuniform float roofPaletteBlend;\nuniform float roofPaletteIntensity;\nuniform vec3 windowColor;\nuniform vec3 litColor;\nuniform float litFraction;\nuniform float litIntensity;\nuniform float facadeIntensity;\nuniform float floorHeight;\nuniform float facadePattern;\n${GLASS_GLSL}\n${PALETTE_GLSL}\n${highlightGlsl("linear")}\nconst float GLINT_SHARPNESS=160.;\nconst float GLINT_STRENGTH=2.;\nconst float PANE_TILT=.04;\n\nconst float PANE_LIFT=.1;\n\nconst float STREET_WIDTH=24.;\nconst float ACROSS_WIDTH=28.;\n\n\nconst float ACROSS_BAY=3.;\nconst vec2 ACROSS_GLASS=vec2(.6,.55);\nuniform sampler2DArray windowProfiles;\nvarying float vHighlightIndex;\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n\n\nfloat facadeBayWidth(float pattern){\nreturn pattern<1.5?3.2:(pattern<2.5?3.:1.6);\n}\n\n\n\nfloat cellCoverage(float x,float share,float footprint){\nfloat covered=1.-smoothstep(-footprint,footprint,abs(fract(x)-.5)-share*.5);\nreturn mix(covered,share,smoothstep(.25,.6,footprint));\n}\n\n\n\n\n\nvec3 mirroredWorld(vec3 direction,vec3 wallNormal,vec3 wallAlong,vec2 spot,vec3 wall,float building,float top,float metresPerPixel,float eyeDistance){\nvec3 skyLight=skyColor*skyIntensity;\nvec2 heading=normalize(direction.xy+1e-4);\nfloat travel=STREET_WIDTH*(.7+.6*facadeHash(vec3(building,2.,5.)))/max(dot(direction,wallNormal),.05);\nvec2 met=spot+vec2(dot(direction,wallAlong),direction.z)*travel;\nfloat footprint=metresPerPixel*(1.+travel/eyeDistance);\nfloat blur=max(footprint,.3);\nvec3 across=vec3(floor(met.x/ACROSS_WIDTH),building,7.);\nfloat acrossTop=max(top,12.)*(.5+.9*facadeHash(across));\n\n\nfloat facesSun=max(dot(-heading,sunDirection.xy),0.)\n*smoothstep(-blur,blur,met.y-acrossTop*(1.-smoothstep(.1,.8,sunDirection.z)));\n\nfloat tone=.45+.5*facadeHash(across+3.1);\nvec2 cell=met/vec2(ACROSS_BAY,floorHeight);\nfloat glass=cellCoverage(cell.x,ACROSS_GLASS.x,footprint/ACROSS_BAY)\n*cellCoverage(cell.y,ACROSS_GLASS.y,footprint/floorHeight);\nfloat lit=mix(step(facadeHash(vec3(floor(cell),building+11.)),litFraction),litFraction,\nsmoothstep(.25,.6,footprint/ACROSS_BAY));\nvec3 facades=mix(wall*tone,windowColor,glass)*(skyLight+sunColor*facesSun)\n+litColor*litIntensity*lit*glass*.8;\nvec3 seen=mix(mirroredStreet(),facades,smoothstep(-blur,blur,met.y));\nreturn mix(seen,mirroredSky(direction),smoothstep(acrossTop-blur,acrossTop+blur,met.y));\n}\n\n\nvoid applyFacade(inout vec3 albedo,out vec3 emissive,out vec3 sunReflection){\nemissive=vec3(0.);\nsunReflection=vec3(0.);\nfloat wallLength=vFacadeFrame.x;\nfloat base=vFacadeFrame.y;\nfloat top=vFacadeFrame.z;\nfloat seed=vFacadeFrame.w;\n\nfloat building=floor(seed*4096.+.5);\nvec3 ownWall=variedColor(wallColors[int(clamp(vFacadeKind.y+.5,0., ${GROUP_COLOR_COUNT-1}.0))],building,seed);\nvec3 wall=highlighted(ownWall,vHighlightIndex);\nfloat height=vFacadeUv.y;\n\nfloat pattern=facadePattern;\nif(pattern>3.5){\npattern=top>=50.?3.:(top>=18.?(seed<.3?3.:2.):1.);\n}\nfloat bayWidth=facadeBayWidth(pattern);\n\nfloat bays=wallLength>0.?floor(wallLength/bayWidth+.5):1.;\nfloat along=vFacadeUv.x/(wallLength>0.?wallLength/max(bays,1.):bayWidth);\nfloat bay=floor(along);\nfloat groundFloor=base<.5&&top>=10.?floorHeight*1.35:0.;\nfloat storeys=floor((top-.8-base-groundFloor)/floorHeight);\nfloat storey=(height-base-groundFloor)/floorHeight;\nbool onGroundFloor=height<base+groundFloor;\nfloat floorIndex=onGroundFloor?-1.:floor(storey);\nfloat onFloor=onGroundFloor?1.:step(0.,floorIndex)*step(floorIndex+.5,storeys);\nfloat windowLayout=onGroundFloor? ${WINDOW_LAYOUTS.length-1}.0:pattern-1.;\nfloat upStorey=onGroundFloor?(height-base)/max(groundFloor,1e-3):storey;\n\n\nfloat window=texture(windowProfiles,vec3(along,.5,windowLayout*2.)).r\n*texture(windowProfiles,vec3(upStorey,.5,windowLayout*2.+1.)).r*onFloor;\n\n\n\n\nfloat bayAveraged=smoothstep(.3,.7,fwidth(along));\nfloat storeyAveraged=smoothstep(.3,.7,fwidth(storey));\nfloat distant=max(bayAveraged,storeyAveraged);\n\n\nfloat panesSharp=1.-smoothstep(.08,.25,max(fwidth(along),fwidth(storey)));\nfloat metresPerPixel=max(fwidth(vFacadeUv.x),fwidth(vFacadeUv.y));\n\nif(vFacadeKind.x>.5){\nvec3 roof=wall*.8;\nif(roofFollowsWalls<.5){\n\nvec3 roofBase=mix(ownWall*.8,roofColor,roofColorSet);\nvec3 ownRoof=roofPaletteCount>.5\n?mix(roofBase,paletteColorAt(roofPaletteColors,roofPaletteCount,roofPaletteBlend,facadeHash(vec3(building,23.,5.))),roofPaletteIntensity)\n:roofBase;\nroof=highlighted(ownRoof,vHighlightIndex);\n}\nalbedo=roof*(.97+.06*facadeHash(vec3(floor(vFacadeUv/3.),building)));\nreturn;\n}\n\n\nfloat occlusion=mix(.7,1.,smoothstep(0.,12.,height));\nalbedo=wall*occlusion;\nif(pattern<.5||top<2.5||bays<1.)return;\n\nvec3 windowSeed=vec3(bay,floorIndex,building);\nvec3 glass=windowColor*mix(.85+.3*facadeHash(windowSeed),1.,distant);\n\nvec3 between=pattern>2.5?mix(wall,windowColor,.45)*occlusion:albedo;\nfloat strength=window*facadeIntensity;\nalbedo=mix(between,glass,strength);\n\nvec3 wallNormal=normalize(vSceneNormal);\n\nvec3 wallAlong=vec3(-wallNormal.y,wallNormal.x,0.);\n\nvec2 tilt=(vec2(facadeHash(windowSeed+5.3),facadeHash(windowSeed+8.9))-.5)*vec2(PANE_TILT,PANE_LIFT)*panesSharp;\nvec3 normal=normalize(wallNormal+tilt.x*wallAlong+vec3(0.,0.,tilt.y));\nfloat eyeDistance=distance(eyePosition,vScenePosition);\nvec3 toEye=(eyePosition-vScenePosition)/eyeDistance;\nvec3 reflected=reflect(-toEye,normal);\n\nfloat mirror=reflectivity*(pattern>2.5?1.:.57)*strength;\nfloat reflectance=mirror*glassFresnel(normal,toEye);\n\nalbedo*=1.-reflectance;\nemissive+=mirroredWorld(reflected,wallNormal,wallAlong,vFacadeUv,ownWall,building,top,metresPerPixel,eyeDistance)\n*reflectance;\n\nsunReflection=sunColor*pow(max(dot(reflected,sunDirection),0.),GLINT_SHARPNESS)*GLINT_STRENGTH*mirror\n+mirroredSun(reflected)*reflectance;\n\nfloat litWindow=1.-step(litFraction,facadeHash(windowSeed+13.7));\n\nfloat litFloor=min(1.,litFraction*(.1+1.8*facadeHash(vec3(-1.,floorIndex,building))));\nfloat lit=mix(mix(litWindow,litFloor,bayAveraged),litFraction,storeyAveraged);\n\nfloat glow=mix(mix(.65+.35*facadeHash(windowSeed+3.1),.2,bayAveraged),.15,storeyAveraged);\nemissive+=litColor*litIntensity*lit*strength*glow;\nalbedo*=1.-.6*lit*strength;\n}\n`)(),toVector=(e,t=new Vector3)=>{const o=setCssColor(new Color,e);return t.set(o.r,o.g,o.b)},FacadeMaterial=class extends MeshLambertMaterial{highlights;facadeUniforms={wallColors:{value:Array.from({length:GROUP_COLOR_COUNT},()=>new Vector3(1,1,1))},roofColor:{value:new Vector3(1,1,1)},roofFollowsWalls:{value:1},roofColorSet:{value:0},roofPaletteColors:{value:Array.from({length:8},()=>new Vector3)},roofPaletteCount:{value:0},roofPaletteBlend:{value:0},roofPaletteIntensity:{value:1},windowColor:{value:new Vector3},litColor:{value:new Vector3},litFraction:{value:0},litIntensity:{value:0},facadeIntensity:{value:1},floorHeight:{value:3.4},facadePattern:{value:PATTERN_INDEX.mixed},skyColor:{value:new Vector3(1,1,1)},skyIntensity:{value:.45},reflectivity:{value:.7},sunDirection:{value:new Vector3(0,0,1)},sunColor:{value:new Vector3(1,1,1)},eyePosition:{value:new Vector3},windowProfiles:{value:createWindowProfiles()},...createPaletteUniforms()};constructor(e){super(),this.highlights=e,this.onBeforeCompile=e=>{Object.assign(e.uniforms,this.facadeUniforms,this.highlights),e.vertexShader=e.vertexShader.replace("#include <common>",`#include <common>\n${VERTEX_DECLARATIONS$1}`).replace("#include <begin_vertex>",`#include <begin_vertex>\n${VERTEX_ASSIGNMENTS$1}`),e.fragmentShader=e.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS$1}`).replace("#include <map_fragment>","#include <map_fragment>\nvec3 facadeEmissive;\nvec3 glassSunReflection;\napplyFacade(diffuseColor.rgb, facadeEmissive, glassSunReflection);").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += facadeEmissive;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setSun(e){towardsSun(e,this.facadeUniforms.sunDirection.value)}setLook(e){const t=this.facadeUniforms;e.wallColorsByGroup.forEach((e,o)=>toVector(e,t.wallColors.value[o])),toVector(e["roofs.color"],t.roofColor.value),t.roofFollowsWalls.value=e.roofsFollowWalls?1:0,setPaletteUniforms(t,e.wallPalette,"linear"),setPaletteChoice({colors:t.roofPaletteColors,count:t.roofPaletteCount,blend:t.roofPaletteBlend,intensity:t.roofPaletteIntensity},e.roofPalette,"linear"),t.roofColorSet.value=e.roofColorSet?1:0,toVector(e["windows.color"],t.windowColor.value),toVector(e["litWindows.color"],t.litColor.value),t.litFraction.value=e["litWindows.fraction"],t.litIntensity.value=1.4*e["litWindows.intensity"],t.facadeIntensity.value=e["facade.intensity"],t.floorHeight.value=e["facade.floorHeightMeters"],t.facadePattern.value=PATTERN_INDEX[e["facade.pattern"]],toVector(e["ambientLight.color"],t.skyColor.value),t.skyIntensity.value=e["ambientLight.intensity"],t.reflectivity.value=e["reflections.intensity"],towardsSun(e,t.sunDirection.value),toVector(e["light.color"],t.sunColor.value).multiplyScalar(e["light.intensity"]),setMaterialOpacity(this,e.opacity)}setEyePosition(e){this.facadeUniforms.eyePosition.value.copy(e)}},GROUND_POINTS=/* @__PURE__ */(()=>[-.0625,.5,1.0625].flatMap(e=>[-.0625,.5,1.0625].map(t=>[e,t])))(),standsOn=(e,t)=>{if(e===t)return!0;const[o,...r]=e.split("/"),[a,...i]=t.split("/");return a===o&&i.every(e=>r.includes(e))},BuildingsLayer=class{landmarksOf;id;type="custom";renderingMode="3d";source={id:BASE_MAP_SOURCE_ID,layer:"buildings"};highlights=new ObjectHighlights;map;renderer;look;filter={withoutLandmarks:!1};origin;frame=0;lastPick;shadowsDrawnFrom=[];sceneVersion=0;scene=new Scene;camera=new Camera;buildings=new Group;landmarks=new Group;material=new FacadeMaterial(this.highlights.uniforms);depthOnly=new MeshBasicMaterial({colorWrite:!1});shadowsOnly=new MeshBasicMaterial({colorWrite:!1,depthWrite:!1});sun=new DirectionalLight;sky=new HemisphereLight;groundReach={value:5e3};ground=new Mesh(new PlaneGeometry(1,1),this.groundMaterial());tiles=/* @__PURE__ */new Map;pending=[];extrusion;groundKeys={dems:"",byTile:/* @__PURE__ */new Map};shadowFromMercator=new Matrix4;drawn=!1;constructor(e,t=()=>{}){this.landmarksOf=t,this.id=e,this.sky.position.set(0,0,1),this.sun.castShadow=!0,this.sun.shadow.normalBias=.4,this.ground.receiveShadow=!0,this.ground.renderOrder=1,this.landmarks.matrixAutoUpdate=!1,this.scene.add(this.buildings,this.landmarks,this.sun,this.sun.target,this.sky,this.ground)}setSun(e){this.look&&(this.look={...this.look,...e},this.sceneVersion++,this.material.setSun(e))}setLook(e){this.look=e,this.sceneVersion++,this.material.setLook(e),this.highlights.setLook(e),setCssColor(this.sun.color,e["light.color"]),this.sun.intensity=e["light.intensity"]*Math.PI,setCssColor(this.sky.color,e["ambientLight.color"]),this.sky.groundColor.copy(this.sky.color).multiplyScalar(.45),this.sky.intensity=e["ambientLight.intensity"]*Math.PI,this.sun.shadow.intensity=e["shadows.intensity"]}onAdd(e,t){this.map=e,this.renderer??=rendererOf(e,t),this.renderer.shadowMap.type=PCFShadowMap,this.renderer.shadowMap.autoUpdate=!1;const o=Math.min(4096,this.renderer.capabilities.maxTextureSize);this.sun.shadow.mapSize.set(o,o)}onRemove(e){setSunShadowMap(e,void 0)}render(e,t){this.lastPick=void 0;const o=this.draw(e,t);this.map&&(o?this.shareShadows(this.map,o.origin,o.look):setSunShadowMap(this.map,void 0))}enableShadowMap(e,t){e.shadowMap.enabled!==t&&(e.shadowMap.enabled=t,this.scene.traverse(e=>{if(isMesh(e))for(const t of[e.material].flat())t.needsUpdate=!0}))}draw(e,t){const{map:o,renderer:r,look:a}=this;if(!o||!r||!a?.visible)return;const i=t.defaultProjectionData.mainMatrix,s=this.landmarksOf(),n=s?.prepareForBuildings(i,this.material.facadeUniforms);if(this.buildings.visible=o.getZoom()>=a.minZoom,this.landmarks.visible=void 0!==n,!this.buildings.visible&&!n)return;this.frame++;const l=void 0!==n;l!==this.filter.withoutLandmarks&&(this.filter={withoutLandmarks:l},this.pending=[],this.extrusion=void 0);const c=this.updateOrigin(o);this.buildings.visible&&this.updateTiles(o,c),s&&n&&this.placeLandmarks(s,n,c),setCameraProjection(this.camera,localFrameMatrix(i,c.position,{centerLatitude:o.getCenter().lat})),this.drawn=!0,this.material.setEyePosition(this.eyePosition()),this.updateSun(o,c,a),this.ground.visible=a["shadows.visible"]&&!o.terrain,this.enableShadowMap(r,a["shadows.visible"]),resetRendererFor(r,e),r.state.buffers.depth.setMask(!0);const d=[];this.buildings.visible&&d.push({group:this.buildings,translucent:a.opacity<1,use:e=>this.useBuildingsPass(e)}),s&&n&&d.push({group:this.landmarks,translucent:n.translucent,use:e=>s.useMaterials(e)});const u=this.shadowsStale(a);return d.some(({translucent:e})=>e)?this.renderTranslucent(r,d,u):(r.shadowMap.needsUpdate=u,r.render(this.scene,this.camera)),{origin:c,look:a}}shareShadows(e,t,o){const r=o["shadows.visible"]?this.sun.shadow.map?.depthTexture:null;if(!r)return void setSunShadowMap(e,void 0);const a=t.metresPerMercator;this.shadowFromMercator.set(a,0,0,-t.x*a,0,-a,0,t.y*a,0,0,1,0,0,0,0,1).premultiply(this.sun.shadow.matrix),setSunShadowMap(e,{texture:r,fromMercator:this.shadowFromMercator,intensity:o["shadows.intensity"],sun:{direction:o["light.direction"],altitude:o["light.altitude"]}})}renderTranslucent(e,t,o){const r=t.filter(e=>e.translucent),a=t.filter(e=>!e.translucent),i=a.map(({group:e})=>e.visible),s=this.ground.visible;if(this.ground.visible=!1,a.length){for(const e of r)e.use("shadows");e.shadowMap.needsUpdate=o,e.render(this.scene,this.camera);for(const{group:e}of a)e.visible=!1}for(const n of r)n.use("depth");e.shadowMap.needsUpdate=!1,e.render(this.scene,this.camera),this.ground.visible=s;for(const n of r)n.use("color");e.shadowMap.needsUpdate=o&&!a.length,e.render(this.scene,this.camera),a.forEach(({group:e},t)=>{e.visible=i[t]})}shadowsStale(e){if(!e["shadows.visible"])return!1;const{camera:t}=this.sun.shadow;let o=0;this.landmarks.traverseVisible(e=>{isMesh(e)&&o++});const r=[t.left,t.right,t.bottom,t.top,t.near,t.far,...this.sun.position.toArray(),...this.landmarks.matrix.elements,o,this.sceneVersion],a=r.some((e,t)=>e!==this.shadowsDrawnFrom[t]);return this.shadowsDrawnFrom=r,a}useBuildingsPass(e){const t={color:this.material,depth:this.depthOnly,shadows:this.shadowsOnly}[e];for(const{mesh:o}of this.tiles.values())o.material=t}placeLandmarks(e,t,o){e.tiles.parent!==this.landmarks&&this.landmarks.add(e.tiles);const r=o.metresPerMercator*MERCATOR_UNITS_PER_EPSG3857_METER,a=this.toScene(o,.5+t.origin.x*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t.origin.y*MERCATOR_UNITS_PER_EPSG3857_METER);this.landmarks.matrix.makeScale(r,r,1).setPosition(a.x,a.y,0),this.landmarks.matrixWorldNeedsUpdate=!0}toScene(e,t,o){return new Vector2((t-e.x)*e.metresPerMercator,(e.y-o)*e.metresPerMercator)}updateOrigin(e){const t=e.getCenter(),o=MercatorCoordinate.fromLngLat(t);if(this.origin&&this.toScene(this.origin,o.x,o.y).length()<2e4)return this.origin;const r=this.origin;return this.origin={x:o.x,y:o.y,position:t.toArray(),metresPerMercator:metersPerMercatorAt(t.lat)},r&&this.carryTiles(r,this.origin),this.pending=[],this.extrusion=void 0,this.origin}carryTiles(e,t){this.sceneVersion++;const o=t.metresPerMercator/e.metresPerMercator,r=this.toScene(t,e.x,e.y);for(const{mesh:a}of this.tiles.values())a.position.set(a.position.x*o+r.x,a.position.y*o+r.y,0),a.scale.set(a.scale.x*o,a.scale.y*o,1)}updateTiles(e,t){const o=((e,t,o,r)=>{const a=/* @__PURE__ */new Map;for(const i of renderedTilesOf(e,t)){if(!i.latestFeatureIndex?.rawTileData)continue;const{x:e,y:t,z:s}=i.tileID.canonical,{wrap:n}=i.tileID,l=`${s}/${e}/${t}/${n}`;a.has(l)||a.set(l,{key:l,tileID:i.tileID,read:()=>readBuildings(i,o,r)})}return a})(e,this.source.id,this.source.layer,this.filter),r=this.sourceKey(),a=((e,t)=>{const o=e.terrain;if(!o)return()=>"";const r=encodeURIComponent(`${e.getTerrain()?.source}@${o.exaggeration}`),a=/* @__PURE__ */new Map;for(const{tileID:s}of o.tileManager.getRenderableTiles()){const e=o.tileManager.getSourceTile(s,!0);if(!e?.dem||a.has(e.tileID.key))continue;const{corner:[t,r],size:i}=tileBoundsOf(e.tileID);a.set(e.tileID.key,[e.tileID.key,t,r,i])}const i=[r,...[...a.keys()].sort((e,t)=>e.localeCompare(t))].join("/");return i!==t.dems&&(t.dems=i,t.byTile.clear()),({key:e,tileID:o})=>{let i=t.byTile.get(e);if(void 0===i){const{corner:[s,n],size:l}=tileBoundsOf(o),c=new Set(GROUND_POINTS.flatMap(([e,t])=>((e,t)=>{let o;for(const r of a.values()){const[,a,i,s]=r;e>=a&&e<a+s&&t>=i&&t<i+s&&(!o||s<o[3])&&(o=r)}return o?.[0]})(s+e*l,n+t*l)??[]));i=[r,...[...c].sort((e,t)=>e.localeCompare(t))].join("/"),t.byTile.set(e,i)}return i}})(e,this.groundKeys);this.queueTiles(a,o,r,t);const i=performance.now()+(e.isMoving()?4:8);for(;this.pending.length&&performance.now()<i;){const o=this.pending[0],s=a(o);if(this.extrusion?.key===o.key&&this.extrusion.source===r&&standsOn(this.extrusion.ground,s)||(this.extrusion={key:o.key,source:r,ground:s,run:this.startExtrusion(e,o,t)}),!this.extrusion.run.extrudeUntil(i))break;this.pending.shift();const n=this.tiles.get(o.key);n&&this.removeTileMesh(n.mesh),this.tiles.set(o.key,{mesh:this.addTileMesh(this.extrusion.run),pieces:this.extrusion.run.pieces,lastSeen:this.frame,source:r,withoutLandmarks:this.filter.withoutLandmarks,origin:t,ground:s}),this.extrusion=void 0}this.pending.length&&e.triggerRepaint();for(const[s,{mesh:n}]of this.tiles){const e=o.has(s);n.visible!==e&&this.sceneVersion++,n.visible=e}this.evictStaleTiles()}sourceKey(){return`${this.source.id}/${this.source.layer}`}queueTiles(e,t,o,r){this.pending=this.pending.flatMap(({key:e})=>t.get(e)??[]);const a=new Set(this.pending.map(({key:e})=>e));for(const i of t.values()){const t=this.tiles.get(i.key);t&&(t.lastSeen=this.frame),t?.source===o&&t.withoutLandmarks===this.filter.withoutLandmarks&&t.origin===r&&standsOn(t.ground,e(i))||a.has(i.key)||this.pending.push(i)}}startExtrusion(e,t,o){const{footprints:r,extent:a}=t.read(),{corner:[i,s],size:n}=tileBoundsOf(t.tileID),l=this.toScene(o,i,s),c=e.terrain?({x:t,y:o})=>groundElevationAt(e,new MercatorCoordinate(i+t/a*n,s+o/a*n).toLngLat()):void 0;return new BuildingsExtrusion(r,{extent:a,originX:l.x,originY:l.y,metresPerUnit:o.metresPerMercator*n/a,groundAt:c},e=>this.highlights.indexOf(e.id,e.properties))}pick(e){const{map:t,look:o}=this;if(!t||!this.drawn||!o?.visible)return;const r=this.lastPick;if(r?.x===e.x&&r.y===e.y)return r.pick;const a=rayThrough(this.camera,e,t.getCanvas()),i=this.buildings.visible?((e,t)=>{let o;const r=new Matrix4;for(const{mesh:a,pieces:i}of t){if(!isShown(a))continue;const t=e.clone().applyMatrix4(r.copy(a.matrixWorld).invert());for(const{piece:r,distance:s}of piecesAlong(e,t,a,i)){if(o&&s>o.distance)break;const i=nearestTriangleOf(e,t,a,r);void 0!==i&&(!o||i<o.distance)&&(o={building:r.index,distance:i})}}return o})(a,this.tiles.values()):void 0,s=(l=this.landmarks.visible?nearestLandmark(a,this.landmarks,i?.distance):void 0,!(n=i)||l&&l.distance<n.distance?l:n);var n,l;return this.lastPick={x:e.x,y:e.y,pick:s},s}addTileMesh(e){this.sceneVersion++;const t=new Mesh(e.toGeometry(),this.material);return t.castShadow=!0,t.receiveShadow=!0,this.buildings.add(t),t}removeTileMesh(e){this.sceneVersion++,this.buildings.remove(e),e.geometry.dispose()}evictStaleTiles(){if(this.tiles.size<=96)return;const e=[...this.tiles].sort(([,e],[,t])=>e.lastSeen-t.lastSeen);for(const[t,{mesh:o}]of e.slice(0,this.tiles.size-96))o.visible||(this.removeTileMesh(o),this.tiles.delete(t))}eyePosition(){const e=new Vector4(0,0,1,0).applyMatrix4(this.camera.projectionMatrixInverse);return 0===e.w?new Vector3:new Vector3(e.x/e.w,e.y/e.w,e.z/e.w)}groundMaterial(){const e=new ShadowMaterial({opacity:.55,depthWrite:!1});return e.onBeforeCompile=e=>{e.uniforms.groundReach=this.groundReach,e.vertexShader=e.vertexShader.replace("#include <common>","#include <common>\nvarying vec2 vGroundUv;").replace("#include <begin_vertex>","#include <begin_vertex>\nvGroundUv = uv;"),e.fragmentShader=e.fragmentShader.replace("#include <common>","#include <common>\nuniform float groundReach;\nvarying vec2 vGroundUv;").replace("#include <fog_fragment>","gl_FragColor.a *= 1.0 - smoothstep(4000.0, 5000.0, length(vGroundUv * 2.0 - 1.0) * groundReach);\n#include <fog_fragment>")},e}groundCornersInView(e,t,o,r){const{clientWidth:a,clientHeight:i}=e.getCanvas(),s=((e,t)=>{const o=e.getPitch(),r=t/2/Math.tan(MathUtils.degToRad(e.getVerticalFieldOfView())/2)*Math.min(.85*Math.tan(MathUtils.degToRad(90-o)),Math.tan(MathUtils.degToRad(89.25-o)));return Math.max(0,t/2-r)})(e,i);return[[0,s],[a,s],[a,i],[0,i]].map(([a,i])=>{const s=e.unproject([a,i]),n=MercatorCoordinate.fromLngLat(s),l=this.toScene(t,n.x,n.y).sub(o).clampLength(0,5e3).add(o);return new Vector3(l.x,l.y,r(s))})}updateSun(e,t,o){const r=t=>groundElevationAt(e,t),a=e.getCenter(),i=MercatorCoordinate.fromLngLat(a),s=this.toScene(t,i.x,i.y),n=r(a);this.sun.target.position.set(s.x,s.y,n),this.sun.position.set(s.x,s.y,n).addScaledVector(towardsSun(o),8e3),this.sun.updateMatrixWorld(),this.sun.target.updateMatrixWorld();const{shadow:l}=this.sun;l.updateMatrices(this.sun);const c=new Box2;let d=0,u=Number.POSITIVE_INFINITY,f=0;for(const _ of this.groundCornersInView(e,t,s,r)){d=Math.max(d,s.distanceTo(_));const e=_.applyMatrix4(l.camera.matrixWorldInverse);c.expandByPoint(new Vector2(e.x,e.y)),u=Math.min(u,-e.z),f=Math.max(f,-e.z)}c.expandByScalar(150);const h=c.getSize(new Vector2).divideScalar(100).ceil().multiplyScalar(100),m=h.clone().divide(l.mapSize),p=(new Vector3).applyMatrix4(l.camera.matrixWorldInverse),g=c.min.clone().sub(p).divide(m).floor().multiply(m).add(p);l.camera.left=g.x,l.camera.right=g.x+h.x,l.camera.bottom=g.y,l.camera.top=g.y+h.y;const v=250/Math.tan(MathUtils.degToRad(o["light.altitude"]));l.camera.near=Math.max(1,u-v-1e3),l.camera.far=f+150+(e.terrain?1e3:0),l.camera.updateProjectionMatrix(),l.bias=-.3/(l.camera.far-l.camera.near),d+=150,this.groundReach.value=d,this.ground.position.set(s.x,s.y,.05),this.ground.scale.set(2*d,2*d,1)}},LAYER_ID="tomtom-3d-buildings",Buildings3D=class extends KnobConfigured{map;buildingsLayer;customLayer;renderedLook;followedLight="";styling;occludedLabels=/* @__PURE__ */new Set;styleOrder=[];constructor(e,t={}){super(t),this.map=e,this.buildingsLayer=new BuildingsLayer(LAYER_ID,()=>landmarksOn.get(e)),buildings3DLookOn.set(e,()=>{const e=this.look();return e.visible?e:void 0}),this.render(),this.customLayer=e.addCustomLayer(this.buildingsLayer,{beforeLayerConfig:"lowest3D",hitTest:e=>this.hitsAt(e),setState:(e,t)=>{this.buildingsLayer.highlights.setState(e,t),this.map.mapLibreMap.triggerRepaint()}}),buildingsPickOn.set(e,e=>this.buildingsLayer.pick(e)),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{this.map.mapReady&&!sameJSON(this.look(),this.renderedLook)?this.render():this.styling&&this.placeLabels()}),this.map._onMapColorsChange(()=>{sameJSON(this.look(),this.renderedLook)||this.render()}),this.map.mapLibreMap.on("render",()=>this.followMapLight()),runWhenMapIsReady(this.map,()=>this.install())}get layer(){return this.buildingsLayer}get events(){return this.customLayer.events}setBuildingColors(e){this.buildingsLayer.highlights.setColors(e),this.map.mapLibreMap.triggerRepaint()}getBuildingColors(){return this.buildingsLayer.highlights.getColors()}applyConfig(e){this.config=e,this.render()}_knobValue(e){return this.lookValue(this.look(),e)}install(e=!1){const t=this.map.mapLibreMap,o=t.getLayer(mapStyleLayerIDs.lowest3D);if(o?.source&&o.sourceLayer&&(this.buildingsLayer.source={id:o.source,layer:o.sourceLayer}),!t.getLayer(LAYER_ID))return this.occludedLabels.clear(),void(e||queueMicrotask(()=>this.install(!0)));if(!o){const e=(e=>{const t=e.getLayersOrder(),o=t.indexOf(mapStyleLayerIDs.lowestLabel);return o>=0?t[o+1]:t.find(t=>"symbol"===e.getLayer(t)?.type)})(t);e&&t.moveLayer(LAYER_ID,e)}this.render()}hitsAt(e){const t=this.buildingsLayer.pick(e),o=t&&"building"in t?this.buildingsLayer.highlights.objectAt(t.building):void 0;return o?[o]:[]}look(){const e=this.map.mapLibreMap,t=this.map.mapReady&&e.getLayer(mapStyleLayerIDs.lowest3D)?e.getPaintProperty(mapStyleLayerIDs.lowest3D,"fill-extrusion-color"):void 0;return((e,t)=>{const o=presetOf(e,t.style),r={...Object.fromEntries(Object.keys(o).map(t=>[t,knobValueIn(e,t)??o[t]])),...resolveBuildingsSun(e,t.style,t.light)},a=o=>knobValueIn(e,o)??t.mapColors.accent??"#2f7df6",i=e.walls?.color??o["walls.color"],s=i?oneColorForEveryGroup(i):t.styleColors??oneColorForEveryGroup("hsl(38, 6%, 90%)"),n=e.roofs?.color??o["roofs.color"],l=s[BUILDING_GROUPS.length],c={colors:resolvePalette(r["roofs.palette"],t.mapColors),mode:r["roofs.paletteMode"],intensity:r["roofs.paletteIntensity"]};return{...r,visible:e.visible??!0,preset:e.preset??"auto","walls.color":l,"roofs.color":n??l,"hover.color":a("hover.color"),"click.color":a("click.color"),wallColorsByGroup:s,roofsFollowWalls:void 0===n&&!c.colors.length,roofColorSet:void 0!==n,wallPalette:{colors:resolvePalette(r["walls.palette"],t.mapColors),mode:r["walls.paletteMode"],intensity:r["walls.paletteIntensity"],variation:r["walls.variation"]},roofPalette:c}})(this.config,{style:standardStyleIdOf(this.map.getStyleInput()),styleColors:groupColorsOfPaint(t),mapColors:this.map.mapColors,light:getMapLight(this.map)})}followMapLight(){const e=this.renderedLook,t=getMapLight(this.map),o=`${t?.direction}/${t?.altitude}`;if(!e||o===this.followedLight)return;this.followedLight=o;const r=resolveBuildingsSun(this.config,standardStyleIdOf(this.map.getStyleInput()),t);r["light.direction"]===e["light.direction"]&&r["light.altitude"]===e["light.altitude"]||(this.renderedLook={...e,...r},this.buildingsLayer.setSun(r),this.map.mapLibreMap.triggerRepaint())}render(){const e=this.look();this.renderedLook=e,this.buildingsLayer.setLook(e),restyleLandmarksOn.get(this.map)?.(),this.map.mapReady&&(this.map.mapLibreMap.getLayer(mapStyleLayerIDs.lowest3D)&&LayerFilterComposer.for(this.map).setClause(mapStyleLayerIDs.lowest3D,"landmarks3d.buildings3D",!e.visible&&void 0),e.visible&&(e["roadLabels.occluded"]||e["pois.occluded"])&&(this.styling??=stylingModuleOf(this.map)),this.styling=publishMapColorsFor(this.map,[...e["walls.palette"],...e["roofs.palette"]],this.styling),(this.styling||this.occludedLabels.size)&&this.placeLabels(),this.map.mapLibreMap.triggerRepaint())}async placeLabels(){const e=await this.styling,t=this.renderedLook,o=this.map.mapLibreMap;if(!e||!t||!o.getLayer(LAYER_ID))return;const r=(o,r)=>t.visible&&r?e.layers.query({group:o}).layerIds:[],a=/* @__PURE__ */new Set([...r("roadLabels",t["roadLabels.occluded"]),...r("pois",t["pois.occluded"])]),i=o.getLayersOrder(),s=i.indexOf(LAYER_ID);for(const n of this.occludedLabels)i.indexOf(n)>s&&this.occludedLabels.delete(n);this.restoreLabels(a),this.occludeLabels(a)}restoreLabels(e){const t=this.map.mapLibreMap;for(const o of this.occludedLabels){if(e.has(o))continue;this.occludedLabels.delete(o);const r=this.styleOrder.slice(this.styleOrder.indexOf(o)+1).find(e=>!this.occludedLabels.has(e)&&t.getLayer(e));t.getLayer(o)&&t.moveLayer(o,r)}}occludeLabels(e){const t=this.map.mapLibreMap,o=t.getLayersOrder(),r=o.indexOf(LAYER_ID);for(const a of e){const e=o.indexOf(a);if(!(this.occludedLabels.has(a)||e<r)){if(this.occludedLabels.size){if(!this.styleOrder.includes(a)){const t=this.styleOrder.indexOf(o[e+1]);this.styleOrder.splice(t<0?this.styleOrder.length:t,0,a)}}else this.styleOrder=[...o];this.occludedLabels.add(a),t.moveLayer(a,LAYER_ID)}}}},buildLandmarksTileURL=()=>{const{commonBaseURL:e,apiKey:t}=TomTomConfig.instance.get();return`${e}/maps/orbis/display/3d/landmarks/tile/{z}/{x}/{y}?${t?`key=${t}&`:""}apiVersion=2`},STREET_LIGHT_LOOK={visible:!0,color:"hsl(38, 6%, 90%)",palette:[],paletteMode:"pick",paletteIntensity:1,variation:0,"hover.color":"#2f7df6","click.color":"#2f7df6","hover.intensity":.35,"click.intensity":.7,texture:"mask",opacity:.7,verticalGradient:!0,minZoom:10,maxZoom:22},textureUseIndexOf=e=>landmarkTextureUses.indexOf(e),LANDMARK_TEXTURE_GLSL=/* @__PURE__ */(()=>`\nuniform int textureUse;\n${landmarkTextureUses.map((e,t)=>`const int TEXTURE_${e.toUpperCase()} = ${t};`).join("\n")}\nconst vec3 LANDMARK_LUMA=vec3(.2126,.7152,.0722);\n\n\nvec3 landmarkTextureMean(sampler2D source,vec2 uv){\nvec4 mean=textureLod(source,uv,16.);\nreturn mean.rgb/max(mean.a,.05);\n}\n\n\n\nfloat landmarkTextureDetail(vec4 texel,vec3 mean){\nreturn clamp(dot(texel.rgb,LANDMARK_LUMA)/max(dot(mean,LANDMARK_LUMA),1e-3),.3,1.8);\n}\n`)(),LANDMARK_COLOR_GLSL=/* @__PURE__ */(()=>`\n${PALETTE_GLSL}\nvec3 landmarkColor(vec3 color,float landmarkId){\nfloat id=floor(landmarkId+.5);\nreturn variedColor(color,id,facadeHash(vec3(id,41.,11.)));\n}\n`)(),VERTEX_SHADER="\nattribute float fillExtrusionGradient;\nattribute float landmarkId;\nattribute float highlightIndex;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\nvarying float vLandmarkId;\nvarying float vHighlightIndex;\n#ifdef USE_ALPHA_MASK\nvarying vec2 vUv;\n#endif\n\nvoid main(){\nvWorldNormal=normalize(mat3(modelMatrix)*normal);\nvGradient= fillExtrusionGradient;\nvLandmarkId= landmarkId;\nvHighlightIndex= highlightIndex;\n#ifdef USE_ALPHA_MASK\nvUv=uv;\n#endif\ngl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.);\n}\n",ALPHA_MASK_FRAGMENT_CHUNK="\n#ifdef USE_ALPHA_MASK\nuniform sampler2D landmarkMap;\nuniform float alphaMaskCutoff;\nvarying vec2 vUv;\n#endif\n",ALPHA_MASK_MAIN_CHUNK="\n#ifdef USE_ALPHA_MASK\nvec4 landmarkTexel=texture2D(landmarkMap,vUv);\nif(landmarkTexel.a<alphaMaskCutoff){\ndiscard;\n}\n#endif\n",FRAGMENT_SHADER=/* @__PURE__ */(()=>`\nuniform vec3 diffuseColor;\nuniform vec3 lightPosition;\nuniform float lightIntensity;\nuniform vec3 lightColor;\nuniform float layerOpacity;\nuniform float verticalGradient;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\nvarying float vLandmarkId;\nvarying float vHighlightIndex;\n${ALPHA_MASK_FRAGMENT_CHUNK}\n${LANDMARK_TEXTURE_GLSL}\n${LANDMARK_COLOR_GLSL}\n${highlightGlsl("srgb")}\n\nvoid main(){\n${ALPHA_MASK_MAIN_CHUNK}\nvec3 paint=ownColor(landmarkColor(diffuseColor,vLandmarkId),vHighlightIndex);\nfloat colorValue=dot(paint,LANDMARK_LUMA);\n#ifdef USE_ALPHA_MASK\nif(textureUse!=TEXTURE_MASK){\nvec3 mean=landmarkTextureMean(landmarkMap,vUv);\nif(textureUse==TEXTURE_COLOR&&!hasOwnColor(vHighlightIndex)){\npaint=sRGBTransferOETF(vec4(landmarkTexel.rgb,1.)).rgb;\ncolorValue=dot(sRGBTransferOETF(vec4(mean,1.)).rgb,LANDMARK_LUMA);\n}else{\npaint*=landmarkTextureDetail(landmarkTexel,mean);\n}\n}\n#endif\npaint=stateColor(paint,vHighlightIndex);\nvec3 normal=normalize(vWorldNormal);\n\n\nif(!gl_FrontFacing){\nnormal=-normal;\n}\n\n\n\nvec3 flattened=vec3(normal.xy,0.);\nvec3 wallNormal=flattened/max(length(flattened),1e-5);\nfloat upness=smoothstep(.4,.8,normal.z);\nnormal=normalize(mix(wallNormal,vec3(0.,0.,1.),upness));\nvec3 color=paint+vec3(.03);\nfloat directional=clamp(dot(normal,lightPosition),0.,1.);\ndirectional=mix(1.-lightIntensity,max(1.-colorValue+lightIntensity,1.),directional);\nif(abs(normal.y)>.001){\ndirectional*=\n(1.-verticalGradient)+\nverticalGradient*clamp(vGradient,mix(.7,.98,1.-lightIntensity),1.);\n}\nvec3 shaded=clamp(\ncolor*directional*lightColor,\nmix(vec3(0.),vec3(.3),vec3(1.)-lightColor),\nvec3(1.)\n);\ngl_FragColor=vec4(shaded,1.)*layerOpacity;\n}\n`)(),DEFAULT_LIGHT_POSITION=/* @__PURE__ */new Vector3(.2875,-.498,.996),parsedColor=/* @__PURE__ */new Color,srgbColor=/* @__PURE__ */new Color,FillExtrusionMaterial=class extends ShaderMaterial{constructor(e,t,o){super({uniforms:{...t,...o,diffuseColor:{value:new Vector3(1,1,1)},lightPosition:{value:DEFAULT_LIGHT_POSITION.clone()},lightIntensity:{value:.5},lightColor:{value:new Vector3(1,1,1)},layerOpacity:{value:1},verticalGradient:{value:1},textureUse:{value:textureUseIndexOf("mask")},...e&&{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}}},...e&&{defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:FRAGMENT_SHADER,side:e?DoubleSide:FrontSide,transparent:!0,blending:CustomBlending,blendSrc:OneFactor,blendDst:OneMinusSrcAlphaFactor})}copyShadingFrom(e){this.uniforms.diffuseColor.value.copy(e.uniforms.diffuseColor.value),this.uniforms.textureUse.value=e.uniforms.textureUse.value,this.uniforms.lightPosition.value.copy(e.uniforms.lightPosition.value),this.uniforms.lightIntensity.value=e.uniforms.lightIntensity.value,this.uniforms.lightColor.value.copy(e.uniforms.lightColor.value),this.uniforms.layerOpacity.value=e.uniforms.layerOpacity.value,this.uniforms.verticalGradient.value=e.uniforms.verticalGradient.value}setTextureUse(e){this.uniforms.textureUse.value=textureUseIndexOf(e)}setDiffuseColor(e){setCssColor(parsedColor,e).getRGB(srgbColor,SRGBColorSpace),this.uniforms.diffuseColor.value.set(srgbColor.r,srgbColor.g,srgbColor.b)}setLayerOpacity(e){this.uniforms.layerOpacity.value=e}setVerticalGradient(e){this.uniforms.verticalGradient.value=e?1:0}setLight(e,t,o,r){const a=Math.cos(t),i=Math.sin(t);this.uniforms.lightPosition.value.set(e.x*a-e.y*i,e.x*i+e.y*a,e.z),this.uniforms.lightIntensity.value=o,this.uniforms.lightColor.value.set(r.r,r.g,r.b)}},FillExtrusionDepthMaterial=class extends ShaderMaterial{constructor(e){super({...e&&{uniforms:{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}},defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:`\n${ALPHA_MASK_FRAGMENT_CHUNK}\nvoid main(){\n${ALPHA_MASK_MAIN_CHUNK}\ngl_FragColor=vec4(0.);\n}\n`,side:e?DoubleSide:FrontSide,colorWrite:!1})}},FRAGMENT_DECLARATIONS=/* @__PURE__ */(()=>`\nuniform float detailIntensity;\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\nvarying float vLandmarkId;\nvarying float vHighlightIndex;\n${GLASS_GLSL}\n${LANDMARK_TEXTURE_GLSL}\n${LANDMARK_COLOR_GLSL}\n${highlightGlsl("linear")}\n\nconst float LANDMARK_REFLECTIVITY=.6;\n`)(),LandmarkFacadeMaterial=class extends MeshLambertMaterial{detailIntensity={value:1};textureUse={value:textureUseIndexOf("detail")};constructor(e,t,o,r){super({map:t?.map??null,alphaTest:t?.cutoff??0,side:t?DoubleSide:FrontSide}),this.onBeforeCompile=t=>{Object.assign(t.uniforms,e,r,o,{detailIntensity:this.detailIntensity,textureUse:this.textureUse}),t.vertexShader=t.vertexShader.replace("#include <common>","#include <common>\n\nattribute float landmarkId;\nattribute float highlightIndex;\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\nvarying float vLandmarkId;\nvarying float vHighlightIndex;\n").replace("#include <begin_vertex>","#include <begin_vertex>\n\nvLandmarkPosition=(modelMatrix*vec4(transformed,1.)).xyz;\nvLandmarkNormal=mat3(modelMatrix)*objectNormal;\nvLandmarkId= landmarkId;\nvHighlightIndex= highlightIndex;\n"),t.fragmentShader=t.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS}`).replace("#include <map_fragment>","\ndiffuseColor.rgb=ownColor(landmarkColor(diffuseColor.rgb,vLandmarkId),vHighlightIndex);\nfloat landmarkGlass=.5;\n#ifdef USE_MAP\nvec4 landmarkTexel=texture2D(map,vMapUv);\ndiffuseColor.a*=landmarkTexel.a;\nif(textureUse!=TEXTURE_MASK){\nfloat detail=landmarkTextureDetail(landmarkTexel,landmarkTextureMean(map,vMapUv));\ndiffuseColor.rgb=textureUse==TEXTURE_COLOR&&!hasOwnColor(vHighlightIndex)\n?landmarkTexel.rgb\n:diffuseColor.rgb*mix(1.,detail,detailIntensity);\nlandmarkGlass=1.-smoothstep(.6,1.2,detail);\n}\n#endif\ndiffuseColor.rgb=stateColor(diffuseColor.rgb,vHighlightIndex);\nvec3 landmarkNormal=normalize(vLandmarkNormal)*(gl_FrontFacing?1.:-1.);\nvec3 landmarkToEye=normalize(eyePosition-vLandmarkPosition);\nvec3 landmarkReflected=reflect(-landmarkToEye,landmarkNormal);\nfloat landmarkReflectance=reflectivity*LANDMARK_REFLECTIVITY*mix(.3,1.,landmarkGlass)\n*(1.-smoothstep(.5,.9,abs(landmarkNormal.z)))\n*glassFresnel(landmarkNormal,landmarkToEye);\nvec3 landmarkMirrored=mix(mirroredStreet(),mirroredSky(landmarkReflected),smoothstep(-.05,.05,landmarkReflected.z));\ndiffuseColor.rgb*=1.-landmarkReflectance;\nvec3 glassSunReflection=mirroredSun(landmarkReflected)*landmarkReflectance;\n").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += landmarkMirrored * landmarkReflectance;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setLook(e){setCssColor(this.color,e.color),this.textureUse.value=textureUseIndexOf(e.texture),this.detailIntensity.value=e.detailIntensity,setMaterialOpacity(this,e.opacity)}},CREASE_ANGLE_RADIANS=Math.PI/6,LANDMARKS_ACCESS={product:"Orbis 3D Landmarks",requestAccessURL:"https://www.tomtom.com/contact-sales/?source_app=docs-portal&source_product=map-display-api-3d"},TranscoderUnavailableError=class extends Error{},reasonOf=e=>e instanceof Error?e.message:String(e),ModelsSource=class{type="models";id;minzoom;maxzoom;map;tiles;scene;loadedTiles=/* @__PURE__ */new Set;accessDenied=!1;sceneOrigin=null;onTileLoaded;ktx2Loader;transcoderReady;gltfLoader;specification;withCredentials;coveringTileKeys=/* @__PURE__ */new Set;retries=/* @__PURE__ */new Map;constructor(e,t){this.id=e,this.minzoom=t.minzoom??0,this.maxzoom=t.maxzoom??22,this.tiles=t.tiles,this.specification=t,this.withCredentials=t.withCredentials??!1,this.scene=new Group,this.ktx2Loader=new KTX2Loader(new LoadingManager).setCrossOrigin("anonymous").setTranscoderPath(t.transcoderPath??""),this.gltfLoader=(new GLTFLoader).setKTX2Loader(this.ktx2Loader).setMeshoptDecoder(MeshoptDecoder)}onAdd(e,t){this.map=e,this.ktx2Loader.detectSupport(t)}updateTiles(){if(0===this.tiles.length||this.accessDenied)return;const e=this.coveringTiles();this.coveringTileKeys=new Set(e.map(e=>e.key));for(const t of e)this.loadTile(t);this.showCoveringTilesOnly()}showCoveringTilesOnly(){for(const e of this.scene.children)e.visible=this.coveringTileKeys.has(e.userData.key)}coveringTiles(){const e={tileSize:this.map._camera.transform.tileSize,minzoom:this.minzoom,maxzoom:this.maxzoom,terrain:this.map.terrain};return this.map.coveringTiles(e)}loadTile(e){if(this.loadedTiles.has(e.key)||Date.now()<(this.retries.get(e.key)?.notBefore??0))return;this.loadedTiles.add(e.key);const t=e.canonical.url(this.tiles,this.map.getPixelRatio(),this.specification.scheme);this.fetchTile(t).then(t=>{this.retries.delete(e.key),t&&(prepareTileMeshes(t),this.rebaseToSceneOrigin(t),t.userData={isTile:!0,key:e.key},t.visible=this.coveringTileKeys.has(e.key),this.scene.add(t),this.map.triggerRepaint(),this.onTileLoaded?.(t,e.key))}).catch(t=>this.reportTileError(e,t))}reportTileError(e,t){if(this.accessDenied)return;const o=t instanceof TomTomMapError?t:new TomTomMapError(`Could not load ${e.toString()}: ${reasonOf(t)}`,{code:"INTERNAL",sourceId:this.id,cause:t});if(this.accessDenied="INVALID_CREDENTIALS"===o.code||"INSUFFICIENT_PERMISSIONS"===o.code,o.canRetry||t instanceof TranscoderUnavailableError){this.loadedTiles.delete(e.key);const t=(this.retries.get(e.key)?.failures??0)+1,o=Math.min(1e3*2**(t-1),6e4);if(this.retries.set(e.key,{failures:t,notBefore:Date.now()+o}),t>1)return}this.map.fire("error",{error:o,sourceId:this.id})}rebaseToSceneOrigin(e){const t=[];if(e.traverse(e=>{isMesh(e)&&t.push(e)}),0===t.length)return;const o=t[0].position,r={x:Math.round(o.x),y:Math.round(o.y)};if(this.sceneOrigin){if(Math.hypot(o.x-this.sceneOrigin.x,o.y-this.sceneOrigin.y)>1e5){const e=r.x-this.sceneOrigin.x,t=r.y-this.sceneOrigin.y;this.scene.traverse(o=>{isMesh(o)&&(o.position.x-=e,o.position.y-=t)}),this.sceneOrigin=r}}else this.sceneOrigin=r;for(const a of t)a.position.x-=this.sceneOrigin.x,a.position.y-=this.sceneOrigin.y}async fetchTile(e){const t=await fetch(e,this.withCredentials?{credentials:"include"}:void 0).catch(async e=>{throw await toTomTomMapRequestError({fetchError:e},{sourceId:this.id})});if(204===t.status||404===t.status)return null;if(!t.ok)throw await toTomTomMapRequestError({response:t},{sourceId:this.id,privatePreviewAccess:LANDMARKS_ACCESS});const o=await t.arrayBuffer();this.transcoderReady??=(async e=>{if(void 0!==this.specification.transcoderPath)return;const{resolveBundledTranscoderUrl:t}=await(import("./bundledTranscoder-DlqNk7PG.js"));e.setURLModifier(t)})(this.ktx2Loader.manager).catch(e=>{throw this.transcoderReady=void 0,new TranscoderUnavailableError(`the KTX2 transcoder failed to load: ${reasonOf(e)}`,{cause:e})}),await this.transcoderReady;const{scene:r}=await this.gltfLoader.parseAsync(o,LoaderUtils.extractUrlBase(e));return r}},prepareTileMeshes=e=>{e.traverse(e=>{if(!isMesh(e))return;const t=e.material;t.alphaTest=.1,t.side=DoubleSide,e.userData.originalMaterial=t,e.castShadow=!0,e.receiveShadow=!0,e.geometry=toCreasedNormals(e.geometry,CREASE_ANGLE_RADIANS),bakeGradientAttribute(e),bakeLandmarkId(e)})},bakeLandmarkId=e=>{const{x:t,y:o}=e.position,r=Math.abs(73856093*Math.round(t)^19349663*Math.round(o));e.userData.landmark={id:r,properties:{position:mercatorMetresToLngLat(t,o)}};const a=new Float32Array(e.geometry.getAttribute("position").count).fill(r%4096);e.geometry.setAttribute("landmarkId",new BufferAttribute(a,1))},bakeGradientAttribute=e=>{const t=e.geometry,o=t.getAttribute("position");t.computeBoundingBox();const r=t.boundingBox?.max.z??0,a=r>0?Math.sqrt(r/150)/r:0,i=new Float32Array(o.count);for(let s=0;s<o.count;s++)i[s]=o.getZ(s)*a;t.setAttribute("fillExtrusionGradient",new BufferAttribute(i,1))},texturedOriginalOf=e=>{const t=e.userData.originalMaterial;return o=t,o?.map?t:void 0;var o},alphaMaskOf=({map:e,alphaTest:t})=>({map:e,cutoff:t}),ModelsLayer=class{id;type="custom";renderingMode="3d";renderer;scene;camera;tiles;directionalLight=new DirectionalLight(16777215,.5);ambientLight=new AmbientLight(16777215,.1);map;source;minzoom=0;maxzoom=22;visible=!0;diffuseColor="#ffffff";highlights=new ObjectHighlights;fillPalette=createPaletteUniforms();facadePalette=createPaletteUniforms();fillExtrusionMaterial=new FillExtrusionMaterial(void 0,this.highlights.uniforms,this.fillPalette);depthPrepassMaterial=new FillExtrusionDepthMaterial;maskedFillExtrusionMaterials=/* @__PURE__ */new Map;facadeMaterials=/* @__PURE__ */new Map;buildingsLight;glass;opacity=1;textureUse="mask";drawn=!1;tilesMainMatrix=/* @__PURE__ */new Float64Array(16);tilesStale=!0;terrainVersion=0;markTilesStale=e=>{this.tilesStale=!0,"source"===e.dataType&&e.sourceId===this.map?.getTerrain()?.source&&this.terrainVersion++};constructor(e,t){this.id=e.id,this.source=new ModelsSource(this.id,t),this.tiles=this.source.scene,this.updateProperties(e)}updateProperties(e){this.visible="none"!==e.layout?.visibility,this.diffuseColor=e.paint?.["models-base-color"]??"#ffffff",this.minzoom=e.minzoom??0,this.maxzoom=e.maxzoom??22}setDirectionalLight(e,t,o){this.directionalLight.position.setFromSphericalCoords(e,MathUtils.degToRad(t),MathUtils.degToRad(o))}onAdd(e,t){this.map=e,this.scene=new Scene,this.tiles=this.source.scene,this.camera=new Camera,this.setDirectionalLight(1.15,90,0),this.scene.add(this.directionalLight,this.ambientLight),this.scene.add(this.tiles),this.renderer??=rendererOf(e,t),this.source.onAdd(e,this.renderer),this.tilesStale=!0,e.off("data",this.markTilesStale),e.on("data",this.markTilesStale)}render(e,t){!this.buildingsLight&&this.prepareFrame(t.defaultProjectionData.mainMatrix)&&(this.tiles.parent!==this.scene&&this.scene.add(this.tiles),this.syncLighting(),this.alignCameraToMap(t),this.drawn=!0,resetRendererFor(this.renderer,e),this.opacity<1&&(this.useMaterials("depth"),this.renderer.render(this.scene,this.camera)),this.applyMaterials(),this.renderer.render(this.scene,this.camera))}pick(e){if(!this.buildingsLight&&this.drawn&&this.tiles.visible)return nearestLandmark(rayThrough(this.camera,e,this.map.getCanvas()),this.tiles)}hitOf(e){const t=e.userData.highlightIndex;return"number"==typeof t?this.highlights.objectAt(t):void 0}prepareForBuildings(e,t){if(this.buildingsLight&&this.map&&!this.source.accessDenied&&this.prepareFrame(e))return t!==this.glass&&(this.facadeMaterials.forEach(e=>e.dispose()),this.facadeMaterials.clear(),this.glass=t),this.applyMaterials(),{origin:this.sceneOrigin,translucent:this.opacity<1}}useMaterials(e){if("depth"!==e){this.applyMaterials();const t="color"===e;return void this.facadeMaterials.forEach(e=>{e.colorWrite=t,e.depthWrite=t})}this.tiles.traverseVisible(e=>{isMesh(e)&&(e.material=this.maskedFillExtrusionVariant(e)?.depth??this.depthPrepassMaterial)})}prepareFrame(e){const t=this.map._camera.transform.tileZoom,o=Math.max(this.minzoom,this.source.minzoom);return this.tiles.visible=this.visible&&t>=o&&t<=this.maxzoom,!!this.tiles.visible&&(this.updateTilesWhenStale(e),this.groundLandmarksOnTerrain(),!0)}updateTilesWhenStale(e){(this.tilesMainMatrix.some((t,o)=>t!==e[o])||this.tilesStale)&&(this.tilesMainMatrix.set(e),this.tilesStale=!1,this.source.updateTiles())}groundLandmarksOnTerrain(){const e=this.map.terrain,t=e?`${e.exaggeration}/${this.terrainVersion}`:"";for(const o of this.tiles.children)o.visible&&o.traverse(e=>{isMesh(e)&&e.userData.groundKey!==t&&(e.userData.groundKey=t,this.groundMeshOnTerrain(e))})}groundMeshOnTerrain(e){const t=this.terrainSamplePoints(e);if(!t)return;let o=null;for(const r of t){const t=this.map.queryTerrainElevation(r);if(null===t)return void(e.position.z=0);(null===o||t<o)&&(o=t)}null!==o&&(e.position.z=o-.5)}terrainSamplePoints(e){let t=e.userData.terrainSamplePoints;if(!t){e.geometry.boundingBox||e.geometry.computeBoundingBox();const o=e.geometry.boundingBox;if(!o||o.isEmpty())return null;const r=e.position.x+this.sceneOrigin.x,a=e.position.y+this.sceneOrigin.y,i=(o.min.x+o.max.x)/2,s=(o.min.y+o.max.y)/2;t=[[i,s],[o.min.x,o.min.y],[o.min.x,o.max.y],[o.max.x,o.min.y],[o.max.x,o.max.y],[i,o.min.y],[i,o.max.y],[o.min.x,s],[o.max.x,s]].map(([e,t])=>mercatorMetresToLngLat(r+e,a+t)),e.userData.terrainSamplePoints=t}return t}alignCameraToMap(e){const t=localFrameMatrix(e.defaultProjectionData.mainMatrix,mercatorMetresToLngLat(this.sceneOrigin.x,this.sceneOrigin.y),{units:"mercatorMeters",centerLatitude:this.map.getCenter().lat});setCameraProjection(this.camera,t)}get sceneOrigin(){return this.source.sceneOrigin??{x:0,y:0}}setOpacity(e){this.opacity=e,this.forEachFillExtrusionMaterial(t=>t.setLayerOpacity(e))}setBuildingsLight(e){this.buildingsLight=e}setPalette(e){setPaletteUniforms(this.fillPalette,e,"srgb"),setPaletteUniforms(this.facadePalette,e,"linear")}setVerticalGradient(e){this.forEachFillExtrusionMaterial(t=>t.setVerticalGradient(e))}setTextureUse(e){this.textureUse=e,this.forEachFillExtrusionMaterial(t=>t.setTextureUse(e))}getMaterial(e){return this.maskedFillExtrusionVariant(e)?.color??this.fillExtrusionMaterial}maskedFillExtrusionVariant(e){const t=texturedOriginalOf(e);if(!t)return null;let o=this.maskedFillExtrusionMaterials.get(t.map);if(!o){const e=alphaMaskOf(t);o={color:new FillExtrusionMaterial(e,this.highlights.uniforms,this.fillPalette),depth:new FillExtrusionDepthMaterial(e)},o.color.copyShadingFrom(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.set(t.map,o)}return o}forEachFillExtrusionMaterial(e){e(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.forEach(t=>e(t.color))}syncLighting(){const e=this.map,t=e.style?.light,o=t?.properties,r=t?.getCartesianPosition?.();if(o&&r)try{const t=o.get("intensity");this.directionalLight.intensity=t*Math.PI,this.ambientLight.intensity=(1-t)*Math.PI;const a={x:-r[0],y:r[1],z:r[2]};this.directionalLight.position.set(a.x,a.y,a.z);const i="viewport"===o.get("anchor")?-(e._camera.transform.bearingInRadians??0):0,s=o.get("color");this.forEachFillExtrusionMaterial(e=>e.setLight(a,i,t,s))}catch{}}applyMaterials(){const{buildingsLight:e,glass:t}=this;if(e&&t){const o={color:this.diffuseColor,texture:this.textureUse,detailIntensity:e["facade.intensity"],opacity:this.opacity};return this.tiles.traverseVisible(e=>{isMesh(e)&&(this.bakeHighlightIndex(e),e.material=this.facadeMaterialOf(e,t))}),void this.facadeMaterials.forEach(e=>e.setLook(o))}this.forEachFillExtrusionMaterial(e=>e.setDiffuseColor(this.diffuseColor)),this.tiles.traverseVisible(e=>{isMesh(e)&&(this.bakeHighlightIndex(e),e.material=this.getMaterial(e))})}bakeHighlightIndex(e){if(void 0!==e.userData.highlightIndex)return;const t=e.userData.landmark,o=t?this.highlights.indexOf(t.id,t.properties):-1;e.userData.highlightIndex=o;const r=new Float32Array(e.geometry.getAttribute("position").count).fill(o);e.geometry.setAttribute("highlightIndex",new BufferAttribute(r,1))}facadeMaterialOf(e,t){const o=texturedOriginalOf(e),r=o?.map??null;let a=this.facadeMaterials.get(r);return a||(a=new LandmarkFacadeMaterial(t,o&&alphaMaskOf(o),this.highlights.uniforms,this.facadePalette),this.facadeMaterials.set(r,a)),a}},NO_LANDMARK_FILTER_CLAUSE=["!",["coalesce",["get","has_landmark"],!1]],Landmarks3D=class{map;layerID="orbis-3d-landmarks";basemapBuildingLayerID=mapStyleLayerIDs.lowest3D;modelsLayer;customLayer;config;renderedLook;styling;constructor(e,{withCredentials:t,transcoderPath:o,...r}={}){this.map=e,this.config=r,restyleLandmarksOn.set(e,()=>this.render());const a={id:this.layerID,type:"models",source:this.layerID},i={type:"models",tiles:[buildLandmarksTileURL()],minzoom:15,maxzoom:15,withCredentials:t??isProxyCredentialsMode(),transcoderPath:o};this.modelsLayer=new ModelsLayer(a,i),landmarksOn.set(e,this.modelsLayer),this.render(),this.customLayer=this.map.addCustomLayer(this.modelsLayer,{beforeLayerConfig:"poi",hitTest:e=>this.hitsAt(e),setState:(e,t)=>{this.modelsLayer.highlights.setState(e,t),this.map.mapLibreMap.triggerRepaint()}}),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{if(!this.map.mapReady)return;const e=this.look();sameJSON(e,this.renderedLook)||this.render(e)}),this.map._onMapColorsChange(()=>this.render()),runWhenMapIsReady(this.map,()=>this.install())}get layer(){return this.modelsLayer}get events(){return this.customLayer.events}setLandmarkColors(e){this.modelsLayer.highlights.setColors(e),this.map.mapLibreMap.triggerRepaint()}getLandmarkColors(){return this.modelsLayer.highlights.getColors()}getConfig(){return structuredClone(this.config)}applyConfig(e){this.config=e,this.render()}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_knobValue(e){return this.look()[e]}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}hitsAt(e){const t=this.modelsLayer.pick(e)??buildingsPickOn.get(this.map)?.(e),o=t&&"landmark"in t?this.modelsLayer.hitOf(t.landmark):void 0;return o?[o]:[]}install(){this.excludeLandmarkBuildingsFromBasemap(),this.modelsLayer.source.onTileLoaded=()=>{this.look().opacity<1&&this.render()},this.render()}excludeLandmarkBuildingsFromBasemap(){LayerFilterComposer.for(this.map).setClause(this.basemapBuildingLayerID,"landmarks3d.buildings",NO_LANDMARK_FILTER_CLAUSE)}readBuildingsLook(){const e=buildings3DLookOn.get(this.map)?.();if(e)return{color:e["walls.color"],"hover.color":e["hover.color"],"hover.intensity":e["hover.intensity"],"click.color":e["click.color"],"click.intensity":e["click.intensity"],palette:e["walls.palette"],paletteMode:e["walls.paletteMode"],paletteIntensity:e["walls.paletteIntensity"],variation:e["walls.variation"],texture:"detail",opacity:e.opacity,verticalGradient:!1,minZoom:e.minZoom};const t=this.map.mapLibreMap,o=this.map.mapColors.accent,r=o?{"hover.color":o,"click.color":o}:{},a=t.getLayer(this.basemapBuildingLayerID);if(!a)return r;const i=e=>t.getPaintProperty(this.basemapBuildingLayerID,e),s=groupColorsOfPaint(i("fill-extrusion-color"))?.at(-1),n=i("fill-extrusion-opacity"),l=i("fill-extrusion-vertical-gradient");return{...r,...s&&{color:s},..."number"==typeof n&&{opacity:n},..."boolean"==typeof l&&{verticalGradient:l},...void 0!==a.minzoom&&{minZoom:a.minzoom},...void 0!==a.maxzoom&&{maxZoom:a.maxzoom}}}look(){const e=this.map.mapReady?this.readBuildingsLook():{},t="streetSatellite"===standardStyleIdOf(this.map.getStyleInput());return((e,t)=>{const o={...STREET_LIGHT_LOOK,...t},r=t=>knobValueIn(e,t)??o[t],a=Object.fromEntries(Object.keys(STREET_LIGHT_LOOK).map(e=>[e,r(e)]));return a.palette=e.palette??(void 0===e.color?o.palette:STREET_LIGHT_LOOK.palette),a})(this.config,t?{...e,texture:"color"}:e)}render(e=this.look()){this.renderedLook=e,this.modelsLayer.visible=e.visible,this.modelsLayer.minzoom=e.minZoom,this.modelsLayer.maxzoom=e.maxZoom,this.modelsLayer.diffuseColor=e.color,this.modelsLayer.setPalette(((e,t)=>({colors:resolvePalette(e.palette,t),mode:e.paletteMode,intensity:e.paletteIntensity,variation:e.variation}))(e,this.map.mapColors)),this.modelsLayer.highlights.setLook(e),this.map.mapReady&&(this.styling=publishMapColorsFor(this.map,e.palette,this.styling)),this.modelsLayer.setTextureUse(e.texture),this.modelsLayer.setOpacity(e.opacity),this.modelsLayer.setVerticalGradient(e.verticalGradient),this.modelsLayer.setBuildingsLight(buildings3DLookOn.get(this.map)?.()),this.map.mapReady&&this.map.mapLibreMap.triggerRepaint()}},STAND_INS=/* @__PURE__ */(()=>[{id:STYLE_LAYER_IDS.landuse,type:"fill","source-layer":"land_use",minzoom:8,filter:["all",["match",["get","group"],["parking","driving"],!1,!0],["match",["get","category"],["construction","facility","pitch"],!1,!0],["!=",["get","underground"],!0]]},{id:STYLE_LAYER_IDS.landcover,type:"fill","source-layer":"land_cover",minzoom:10},{id:STYLE_LAYER_IDS.outdoorAndSport,type:"fill","source-layer":"land_use",minzoom:13,filter:["all",["match",["get","category"],["facility","pitch"],!0,!1],["!=",["get","underground"],!0]]},{id:STYLE_LAYER_IDS.water,type:"fill","source-layer":"water",filter:["!=",["get","intermittent"],!0]},{id:STYLE_LAYER_IDS.buildings,type:"fill","source-layer":"buildings",minzoom:15,filter:["all",["!=",["get","underground"],!0],["!=",["get","part"],!0]]}])(),hash_default="uint hashOf(uvec2 v){v=v*1664525u+1013904223u;v.x+=v.y*1664525u;v.y+=v.x*1664525u;v^=v>>16u;v.x+=v.y*1664525u;v.y+=v.x*1664525u;v^=v>>16u;return v.x;}vec2 halvesOf(uint hash){return vec2(float(hash&0xffffu),float(hash>>16u))*(1./65535.);}\n",math_default="const float TAU=6.2831853;const float HALF_TURN=3.14159265;float luminanceOf(vec3 color){return dot(color,vec3(.2126,.7152,.0722));}\n",terrain_default="uniform highp sampler2D u_dem;uniform highp mat4 u_dem_matrix;uniform highp vec4 u_dem_unpack;uniform highp float u_dem_dim;uniform highp float u_dem_exaggeration;float demAt(ivec2 texel){vec4 rgb=texelFetch(u_dem,texel,0)*255.*u_dem_unpack;return rgb.r+rgb.g+rgb.b-u_dem_unpack.a;}float groundElevationAt(vec2 position){if(u_dem_exaggeration==0.)return 0.;vec2 coord=(u_dem_matrix*vec4(position,0.,1.)).xy*u_dem_dim+1.5;vec2 f=fract(coord);ivec2 c=ivec2(floor(coord));ivec2 last=textureSize(u_dem,0)-1;float topLeft=demAt(clamp(c,ivec2(0),last));float topRight=demAt(clamp(c+ivec2(1,0),ivec2(0),last));float bottomLeft=demAt(clamp(c+ivec2(0,1),ivec2(0),last));float bottomRight=demAt(clamp(c+ivec2(1,1),ivec2(0),last));return mix(mix(topLeft,topRight,f.x),mix(bottomLeft,bottomRight,f.x),f.y)*u_dem_exaggeration;}vec4 projectTileOnGround(vec2 position,float elevation){return u_dem_exaggeration>0.?projectTileFor3D(position,elevation):projectTileWithElevation(position,elevation);}\n",TREE_PARTS={trunk:0,broadleaf:1,conifer:2},TREE_VERTEX_LAYOUT=[{name:"a_position",size:3},{name:"a_normal",size:3},{name:"a_center",size:3},{name:"a_info",size:3}],TREE_VERTEX_FLOATS=/* @__PURE__ */TREE_VERTEX_LAYOUT.reduce((e,{size:t})=>e+t,0),add=(e,t,o,r,a,i,s)=>(e.vertices.push(...t,...(([e,t,o])=>{const r=Math.hypot(e,t,o)||1;return[e/r,t/r,o/r]})(o),...r,a,i,s),e.count++),addCrown=(e,t,o)=>{const{points:r,faces:a}=(e=>{const t=new IcosahedronGeometry(1,e);t.deleteAttribute("uv"),t.deleteAttribute("normal");const o=mergeVertices(t),r=o.getAttribute("position"),a=o.getIndex();return{points:Array.from({length:r.count},(e,t)=>[r.getX(t),r.getY(t),r.getZ(t)]),faces:Array.from({length:(a?.count??0)/3},(e,t)=>[a?.getX(3*t)??0,a?.getX(3*t+1)??0,a?.getX(3*t+2)??0])}})(o);t.forEach(({center:o,radius:i,height:s},n)=>{const l=e.count;for(const[a,c,d]of r){const r=[o[0]+a*i,o[1]+c*i,o[2]+d*s],l=[a/i,c/i,d/s],u=Math.hypot(r[0],r[1]);let f=(.55+.45*(.5+.5*d))*(.85+.15*(u>.001?(r[0]*a+r[1]*c)/u:0));t.forEach((e,t)=>{if(t===n)return;const o=Math.hypot((r[0]-e.center[0])/e.radius,(r[1]-e.center[1])/e.radius,(r[2]-e.center[2])/e.height);f*=.55+.45*MathUtils.clamp((o-.85)/.45,0,1)}),add(e,r,l,o,TREE_PARTS.broadleaf,n,f)}for(const[t,r,c]of a)e.indices.push(l+t,l+r,l+c)})},addTier=(e,{base:t,top:o,radius:r},a,i,s)=>{const n=[0,0,(t+o)/2],l=o-t,c=Array.from({length:a},(e,t)=>{const o=t/a*Math.PI*2,s=r*(t%2==0?1:1-i);return{direction:[Math.cos(o),Math.sin(o)],reach:s}}),d=add(e,[0,0,o],[0,0,1],n,TREE_PARTS.conifer,s,1),u=c.map(({direction:[o,a],reach:i})=>add(e,[o*i,a*i,t],[o*l,a*l,r],n,TREE_PARTS.conifer,s,.62)),f=add(e,[0,0,t+.18*l],[0,0,-1],n,TREE_PARTS.conifer,s,.3),h=c.map(({direction:[o,r],reach:a})=>add(e,[o*a,r*a,t],[.4*o,.4*r,-1],n,TREE_PARTS.conifer,s,.4));for(let m=0;m<a;m++){const t=(m+1)%a;e.indices.push(d,u[m],u[t],f,h[t],h[m])}},meshOf=e=>{const t={vertices:[],indices:[],count:0};return e(t),{vertices:new Float32Array(t.vertices),indices:new Uint16Array(t.indices)}},BROADLEAF_LOBES=/* @__PURE__ */(()=>[{center:[0,0,.62],radius:.3,height:.27},...[0,1,2].map(e=>({center:[.17*Math.cos(2.1*e+.5),.17*Math.sin(2.1*e+.5),.5+.09*e],radius:.2,height:.18}))])(),CONIFER_TIERS=[{base:.13,top:.54,radius:.27},{base:.36,top:.78,radius:.2},{base:.58,top:1,radius:.13}],viewMatrix=/* @__PURE__ */new Matrix4,frustum=/* @__PURE__ */new Frustum,box=/* @__PURE__ */new Box3,sharedConstantsGlsl=()=>[...surfaceKinds.map(e=>`const int ${e.toUpperCase()} = ${SURFACE_IDS[e]};`),`const int SURFACE_ID_COUNT = ${SURFACE_ID_COUNT};`,`const float EXTENT = ${8192..toFixed(1)};`,`const float PERIOD = ${4096..toFixed(1)};`,"const int FIELD_BLOCK = 4;","const int GRID = 32;","const int FINEST = 17;",`const float MAX_HEIGHT = ${40..toFixed(1)};`,...Object.entries(TREE_PARTS).map(([e,t])=>`const int ${e.toUpperCase()}_PART = ${t};`)].join("\n"),uniformsHolding=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{value:t}])),wrappedTextures=/* @__PURE__ */new WeakMap,rawMaterial=e=>new RawShaderMaterial({glslVersion:GLSL3,side:DoubleSide,depthTest:!1,depthWrite:!1,...e}),vertexIdGeometry=(e,t)=>(e.setDrawRange(0,t),e),placedByShader=e=>(e.frustumCulled=!1,e.matrixAutoUpdate=!1,e.matrixWorldAutoUpdate=!1,e),fullscreenPass=e=>placedByShader(new Mesh(vertexIdGeometry(new BufferGeometry,3),rawMaterial({...e,vertexShader:"void main(){vec2 corner=vec2(float((gl_VertexID<<1)&2),float(gl_VertexID&2));gl_Position=vec4(corner*2.-1.,0.,1.);}\n"}))),PASS_CAMERA=/* @__PURE__ */new Camera,drawPass=(e,t)=>e.render(t,PASS_CAMERA),TilePass=class{material;objectOf;scene=Object.assign(new Scene,{matrixWorldAutoUpdate:!1});objects=[];setTileUniforms=()=>{};constructor(e,t){this.material=e,this.objectOf=t}show(e,t){this.setTileUniforms=t;for(let o=this.objects.length;o<e;o++){const e=this.objectOf(this.material);placedByShader(e),e.renderOrder=o,e.onBeforeRender=e=>{this.setTileUniforms(e,o),this.material.uniformsNeedUpdate=!0},this.scene.add(e),this.objects.push(e)}this.objects.forEach((t,o)=>{t.visible=o<e})}},disposePass=({geometry:e,material:t})=>{e.dispose(),t.dispose()},DrawingBufferCopy=class{texture;copy(e,t){let o=this.texture;return o?.image.width===t.drawingBufferWidth&&o.image.height===t.drawingBufferHeight||(o?.dispose(),o=new FramebufferTexture(t.drawingBufferWidth,t.drawingBufferHeight),o.format=RGBFormat,o.internalFormat="RGB8",this.texture=o),e.copyFramebufferToTexture(o),o}dispose(){this.texture?.dispose(),this.texture=void 0}},fieldTarget=([e,t],o=1,r=NearestFilter,a=!1)=>new WebGLRenderTarget(e,t,{count:o,format:RGBAFormat,type:UnsignedByteType,minFilter:r,magFilter:r,generateMipmaps:!1,depthBuffer:a}),FieldRenderer=class{resources;release(){const e=this.resources;if(!e)return;const{passes:t,targets:o}=this.partsOf(e);for(const r of t)disposePass(r);for(const r of o)r.dispose();this.resources=void 0}ensureResources(e){const t=(e=>[Math.ceil(e.drawingBufferWidth/4),Math.ceil(e.drawingBufferHeight/4)])(e),o=this.resources??this.createResources(t);this.resources=o;for(const r of this.partsOf(o).targets)r.setSize(...t);return o}},drawInto=(e,t,o)=>{e.setRenderTarget(t),drawPass(e,o),e.setRenderTarget(null)},tileGroundUniforms=()=>uniformsHolding({u_projection_matrix:/* @__PURE__ */new Float32Array(16),u_projection_fallback_matrix:/* @__PURE__ */new Float32Array(16),u_projection_tile_mercator_coords:[0,0,0,0],u_projection_clipping_plane:[0,0,0,0],u_projection_transition:0,u_dem:null,u_dem_matrix:/* @__PURE__ */new Float32Array(16),u_dem_unpack:[0,0,0,0],u_dem_dim:0,u_dem_exaggeration:0}),vertexSourceOf=({shaderData:e},...t)=>[e.vertexShaderPrelude,e.define,sharedConstantsGlsl(),hash_default,math_default,terrain_default,...t].join("\n"),fragmentSourceOf=(...e)=>["precision highp float;","precision highp int;",sharedConstantsGlsl(),hash_default,math_default,...e].join("\n"),tilePlacementOf=(e,{metersPerMercator:t,camera:o})=>{const{corner:r,size:a}=tileBoundsOf(e),i=a/8192;return{origin:[r[0]*t,r[1]*t],camera:[(r[0]-o[0])*t,(r[1]-o[1])*t],scale:i*t}},projectionOf=(e,{canonical:t,wrap:o})=>e.getProjectionData({tileID:{canonical:t,wrap:o},applyGlobeMatrix:!0}),terrainTilesOf=e=>e.terrain?.tileManager.getRenderableTiles().map(({tileID:e})=>e)??[],intoHolder=/* @__PURE__ */new Matrix4,ontoTerrain=/* @__PURE__ */new Matrix4,tileTerrainOf=(e,{canonical:t,wrap:o},r)=>{const a=e.terrain;if(!a)return;const i=r.find(e=>{const r=2**(e.canonical.z-t.z);return e.wrap===o&&Math.floor((t.x+.5)*r)===e.canonical.x&&Math.floor((t.y+.5)*r)===e.canonical.y});if(!i)return;const s=a.getTerrainData(i),n=2**(i.canonical.z-t.z);return intoHolder.makeScale(n,n,1).setPosition(8192*(t.x*n-i.canonical.x),8192*(t.y*n-i.canonical.y),0),{texture:s.texture,matrix:new Float32Array(ontoTerrain.fromArray(s.u_terrain_matrix).multiply(intoHolder).elements),unpack:s.u_terrain_unpack,dim:s.u_terrain_dim,exaggeration:s.u_terrain_exaggeration}},setTileGround=(e,t,o,r)=>{t.u_projection_matrix.value.set(o.mainMatrix),t.u_projection_fallback_matrix.value.set(o.fallbackMatrix),t.u_projection_tile_mercator_coords.value=o.tileMercatorCoords,t.u_projection_clipping_plane.value=o.clippingPlane,t.u_projection_transition.value=o.projectionTransition,t.u_dem_exaggeration.value=r?.exaggeration??0,t.u_dem.value=r?((e,t)=>{let o=wrappedTextures.get(t);return o||(o=new Texture,e.properties.get(o).__webglTexture=t,wrappedTextures.set(t,o)),o})(e,r.texture):null,r&&(t.u_dem_matrix.value=r.matrix,t.u_dem_unpack.value=r.unpack,t.u_dem_dim.value=r.dim)},landField_default="const int NO_SEED=0xffff;uniform mat3 u_meters_from_clip;vec4 encodeSeed(ivec2 pixel){return vec4(float(pixel.x>>8),float(pixel.x&255),float(pixel.y>>8),float(pixel.y&255))/255.;}ivec2 decodeSeed(vec4 texel){ivec4 bytes=ivec4(round(texel*255.));return ivec2(bytes.r*256+bytes.g,bytes.b*256+bytes.a);}vec2 metersAt(vec2 pixel){vec3 ground=u_meters_from_clip*vec3(pixel/u_viewport*2.-1.,1.);return ground.z>0.?ground.xy/ground.z:vec2(1e9);}const float SHORE_REACH=48.;const int SHORE_DIRECTIONS=8;const float FETCH=256.;vec2 shoreDirection(int index){float angle=(float(index)+.3)*TAU/float(SHORE_DIRECTIONS);return vec2(cos(angle),sin(angle));}float insideViewBy(vec2 pixel){return min(min(pixel.x,pixel.y),min(u_viewport.x-pixel.x,u_viewport.y-pixel.y));}\n",masks_default="uniform vec2 u_viewport;float keyOver(vec3 before,vec3 mask,out int id){vec2 toKey=vec2(1.,0.)-before.gb;float keyDistance=dot(toKey,toKey);float coverage=keyDistance>1e-4?clamp(dot(mask.gb-before.gb,toKey)/keyDistance,0.,1.):0.;id=0;if(coverage<.2)return 0.;float red=(mask.r-before.r*(1.-coverage))/coverage*255.;id=int(red/16.);if(id<=0||id>=SURFACE_ID_COUNT||abs(red-float(id)*16.-8.)>2.5/coverage)id=0;return id>0?coverage:0.;}bool isKeyedAs(sampler2D mask,ivec2 pixel,int id){vec3 color=texelFetch(mask,pixel,0).rgb;return color.g>.98&&color.b<.02&&int(color.r*255./16.)==id;}\n",roadField_default="struct RoadAxis{vec2 across;float offset;float halfWidth;float sureness;};vec2 roadBlockCenter(ivec2 block){return vec2(block*FIELD_BLOCK)+.5*float(FIELD_BLOCK);}vec4 encodeRoadAxis(float direction,float offset,float halfWidth,float sureness){return vec4(direction/HALF_TURN,.5+.5*clamp(offset/halfWidth,-1.,1.),halfWidth/255.,sureness);}RoadAxis decodeRoadAxis(vec4 texel){float direction=texel.r*HALF_TURN;float halfWidth=texel.b*255.;return RoadAxis(vec2(-sin(direction),cos(direction)),(texel.g*2.-1.)*halfWidth,halfWidth,texel.a);}\n",roles_default="uniform sampler2D u_roles;vec3 shaded(vec3 color,int role){vec4 toward=texelFetch(u_roles,ivec2(role,1),0);return mix(color*texelFetch(u_roles,ivec2(role,0),0).rgb,toward.rgb,toward.a);}\n",fieldPassOf=(e,t,o)=>fullscreenPass({name:e,fragmentShader:fragmentSourceOf(masks_default,landField_default,t),uniforms:uniformsHolding({...Object.fromEntries(o.map(e=>[e,null])),u_viewport:[0,0],u_meters_from_clip:null,u_clip_from_meters:null,u_jump:0})}),groundRowsOf=(e,t)=>{const o=o=>[e[o],e[4+o],e[12+o]+e[8+o]*t];return[o(0),o(1),o(3)]},LandFieldRenderer=class extends FieldRenderer{build(e,t,o,{metersFromClip:r,clipFromMeters:a}){const{seed:i,jump:s,openness:n,targets:l,opennessTarget:c}=this.ensureResources(t),d=i.material.uniforms,u=s.material.uniforms,f=n.material.uniforms,h=[t.drawingBufferWidth,t.drawingBufferHeight];for(const v of[d,u,f])v.u_viewport.value=h,v.u_meters_from_clip.value=r;d.u_mask.value=o,drawInto(e,l[0],i);const{width:m,height:p}=l[0];let g=0;for(let v=2**Math.floor(Math.log2(Math.max(m,p)));v>=1;v/=2)u.u_jump.value=v,u.u_field.value=l[g].texture,drawInto(e,l[1-g],s),g=1-g;return f.u_mask.value=o,f.u_field.value=l[g].texture,f.u_clip_from_meters.value=a,drawInto(e,c,n),{field:l[g].texture,openness:c.texture}}createResources(e){return{seed:fieldPassOf("surfaces land seeds","uniform sampler2D u_mask;out vec4 fragColor;void main(){ivec2 origin=ivec2(gl_FragCoord.xy)*FIELD_BLOCK;ivec2 size=ivec2(u_viewport);int land=0;vec2 waterSum=vec2(0.);float waterCount=0.;for(int index=0;index<FIELD_BLOCK*FIELD_BLOCK;index++){ivec2 offset=ivec2(index%FIELD_BLOCK,index/FIELD_BLOCK);ivec2 pixel=origin+offset;if(any(greaterThanEqual(pixel,size)))continue;if(isKeyedAs(u_mask,pixel,WATER)){waterSum+=vec2(offset);waterCount+=1.;}else{land|=1<<index;}}if(land==0){fragColor=vec4(1.);return;}vec2 towards=waterCount>0.?waterSum/waterCount:vec2(float(FIELD_BLOCK-1)*.5);float nearest=1e9;ivec2 seed=origin;for(int index=0;index<FIELD_BLOCK*FIELD_BLOCK;index++){if(((land>>index)&1)==0)continue;vec2 offset=vec2(index%FIELD_BLOCK,index/FIELD_BLOCK);float distance=dot(offset-towards,offset-towards);if(distance<nearest){nearest=distance;seed=origin+ivec2(offset);}}fragColor=encodeSeed(seed);}\n",["u_mask"]),jump:fieldPassOf("surfaces land jump","uniform sampler2D u_field;uniform int u_jump;out vec4 fragColor;void main(){ivec2 texel=ivec2(gl_FragCoord.xy);ivec2 size=textureSize(u_field,0);vec2 here=metersAt((vec2(texel)+.5)*float(FIELD_BLOCK));float nearest=1e30;vec4 kept=vec4(1.);for(int y=-1;y<=1;y++){for(int x=-1;x<=1;x++){ivec2 neighbour=texel+ivec2(x,y)*u_jump;if(any(lessThan(neighbour,ivec2(0)))||any(greaterThanEqual(neighbour,size)))continue;vec4 candidate=texelFetch(u_field,neighbour,0);ivec2 seed=decodeSeed(candidate);if(seed.x==NO_SEED)continue;vec2 away=metersAt(vec2(seed)+.5)-here;float distance=dot(away,away);if(distance<nearest){nearest=distance;kept=candidate;}}}fragColor=kept;}\n",["u_field"]),openness:fieldPassOf("surfaces land openness","uniform sampler2D u_mask;uniform sampler2D u_field;uniform mat3 u_clip_from_meters;out vec4 fragColor;vec2 pixelOfMeters(vec2 meters){vec3 clip=u_clip_from_meters*vec3(meters,1.);return clip.z>0.?(clip.xy/clip.z*.5+.5)*u_viewport:vec2(-1e9);}float openWaterAt(vec2 meters,out float known){vec2 pixel=pixelOfMeters(meters);known=smoothstep(0.,.08*min(u_viewport.x,u_viewport.y),insideViewBy(pixel));ivec2 texel=ivec2(pixel);if(known<=0.||!isKeyedAs(u_mask,texel,WATER))return 0.;ivec2 seed=decodeSeed(texelFetch(u_field,texel/FIELD_BLOCK,0));if(seed.x==NO_SEED)return 1.;return smoothstep(0.,24.,distance(metersAt(vec2(seed)+.5),meters));}void main(){vec2 here=metersAt(gl_FragCoord.xy*float(FIELD_BLOCK));float open=0.;float known=0.;vec2 landward=vec2(0.);for(int index=0;index<SHORE_DIRECTIONS;index++){vec2 direction=shoreDirection(index);float nearKnown;float farKnown;float near=openWaterAt(here+direction*SHORE_REACH,nearKnown);float far=openWaterAt(here+direction*FETCH,farKnown);open+=nearKnown*near*mix(1.,far,farKnown);known+=nearKnown;landward+=direction*(.65*nearKnown*(1.-near)+.35*farKnown*(1.-far));}float openness=mix(1.,open/max(known,1e-3),clamp(known/2.,0.,1.));fragColor=vec4(openness,clamp(landward*.3,-1.,1.)*.5+.5,1.);}\n",["u_mask","u_field"]),targets:[fieldTarget(e),fieldTarget(e)],opennessTarget:fieldTarget(e,1,LinearFilter)}}partsOf({seed:e,jump:t,openness:o,targets:r,opennessTarget:a}){return{passes:[e,t,o],targets:[...r,a]}}},RoadFieldRenderer=class extends FieldRenderer{build(e,t,o){const{pass:r,target:a}=this.ensureResources(t),{uniforms:i}=r.material;return i.u_viewport.value=[t.drawingBufferWidth,t.drawingBufferHeight],i.u_mask.value=o,drawInto(e,a,r),a.texture}createResources(e){return{pass:fullscreenPass({name:"surfaces road axes",fragmentShader:fragmentSourceOf(masks_default,roadField_default,"uniform sampler2D u_mask;out vec4 fragColor;const int ROAD_DIRECTIONS=16;const float ROAD_REACH=128.;bool isRoadAt(vec2 pixel){if(any(lessThan(pixel,vec2(0.)))||any(greaterThanEqual(pixel,u_viewport)))return true;return isKeyedAs(u_mask,ivec2(pixel),ROADS);}float runAlong(vec2 origin,vec2 direction){float inside=0.;float outside=ROAD_REACH;for(float step=1.;step<=ROAD_REACH;step*=2.){if(!isRoadAt(origin+direction*step)){outside=step;break;}inside=step;}if(inside>=ROAD_REACH)return ROAD_REACH;for(int halving=0;halving<3;halving++){float middle=.5*(inside+outside);if(isRoadAt(origin+direction*middle))inside=middle;else outside=middle;}return .5*(inside+outside);}void main(){vec2 origin=roadBlockCenter(ivec2(gl_FragCoord.xy));fragColor=vec4(0.);if(!isRoadAt(origin))return;float runs[ROAD_DIRECTIONS];for(int index=0;index<ROAD_DIRECTIONS;index++){float angle=float(index)*TAU/float(ROAD_DIRECTIONS);runs[index]=runAlong(origin,vec2(cos(angle),sin(angle)));}vec2 axis=vec2(0.);float total=0.;for(int index=0;index<ROAD_DIRECTIONS/2;index++){float extent=runs[index]+runs[index+ROAD_DIRECTIONS/2];float angle=float(index)*TAU/float(ROAD_DIRECTIONS/2);axis+=extent*extent*vec2(cos(angle),sin(angle));total+=extent*extent;}float sureness=length(axis)/total;if(sureness<.25)return;float direction=mod(.5*atan(axis.y,axis.x),HALF_TURN);vec2 across=vec2(-sin(direction),cos(direction));float plus=runAlong(origin,across);float minus=runAlong(origin,-across);float halfWidth=.5*(plus+minus);if(halfWidth>=.9*ROAD_REACH)return;fragColor=encodeRoadAxis(direction,.5*(plus-minus),halfWidth,sureness);}\n"),uniforms:uniformsHolding({u_mask:null,u_viewport:[0,0]})}),target:fieldTarget(e)}}partsOf({pass:e,target:t}){return{passes:[e],targets:[t]}}},PALETTE_ROLES={water:["ground","shallow","foam"],ice:["ground","crevasses"],forest:["ground","broadleaf","conifer"],grass:["ground","lush","dry","flowers"],scrub:["ground","bushes"],farmland:["ground","young","cereal","soil","pasture","rapeseed","stubble","hedges"],sand:["ground","wet"],mud:["ground","wet"],gravel:["ground"],rock:["ground"],paving:["ground","joints"],urban:["ground"],roads:["ground"],trees:["broadleaf","conifer"]},SNOW="#f2f5f8",PALETTES={water:{spring:{ground:{tint:[.98,1.03,1]},shallow:{tint:[1.04,1.12,1.04],toward:"#ffffff",weight:.04},foam:{toward:"#ffffff",weight:.8}},summer:{shallow:{tint:[1.04,1.1,1.06],toward:"#ffffff",weight:.03},foam:{toward:"#ffffff",weight:.8}},autumn:{ground:{tint:[.94,.96,.92]},shallow:{tint:[1.04,1.06,.98],toward:"#ffffff",weight:.03},foam:{toward:"#f4f1ea",weight:.75}},winter:{ground:{tint:[.86,.93,.98]},shallow:{tint:[.98,1.05,1.08],toward:"#ffffff",weight:.06},foam:{toward:"#ffffff",weight:.8}},snow:{ground:{tint:[.84,.92,.98]},shallow:{toward:"#e6eef2",weight:.55},foam:{toward:"#ffffff",weight:.85}}},ice:{spring:{crevasses:{tint:[.7,.84,1],toward:"#6f9fc4",weight:.35}},summer:{crevasses:{tint:[.68,.84,1],toward:"#5f94bf",weight:.4}},autumn:{crevasses:{tint:[.7,.84,1],toward:"#6f9fc4",weight:.35}},winter:{crevasses:{tint:[.74,.86,1],toward:"#7ea7c6",weight:.3}},snow:{ground:{toward:SNOW,weight:.4},crevasses:{tint:[.8,.9,1],toward:"#9dbad0",weight:.3}}},forest:{spring:{ground:{tint:[1.02,1.06,.96]},broadleaf:{tint:[1.04,1.12,.84],toward:"#b5d86a",weight:.18},conifer:{tint:[.62,.78,.64]}},summer:{conifer:{tint:[.6,.74,.64]}},autumn:{ground:{tint:[1.04,.98,.86]},broadleaf:{tint:[1.1,.92,.68],toward:"#c9772f",weight:.5},conifer:{tint:[.6,.72,.62]}},winter:{ground:{tint:[.96,.94,.9],toward:"#8c857b",weight:.35},broadleaf:{toward:"#857c70",weight:.65},conifer:{tint:[.56,.68,.62]}},snow:{ground:{toward:SNOW,weight:.82},broadleaf:{toward:"#cfd4d8",weight:.75},conifer:{tint:[.55,.66,.62],toward:SNOW,weight:.25}}},grass:{spring:{ground:{tint:[.95,1.06,.9]},lush:{tint:[.9,1.08,.86]},dry:{tint:[1,1.06,.9]},flowers:{toward:"#f7d94c",weight:1}},summer:{lush:{tint:[.94,1.02,.93]},dry:{tint:[1.08,1.04,.85]},flowers:{toward:"#fae06b",weight:1}},autumn:{ground:{tint:[1.05,1,.84]},lush:{tint:[1,1,.88]},dry:{tint:[1.12,1,.74]},flowers:{toward:"#c98a4b",weight:1}},winter:{ground:{tint:[1.02,.98,.88],toward:"#a59e8c",weight:.25},lush:{tint:[.96,.98,.9]},dry:{tint:[1.06,1,.84],toward:"#b8ae98",weight:.2},flowers:{toward:"#ddd8cc",weight:1}},snow:{ground:{toward:SNOW,weight:.88},lush:{toward:"#ffffff",weight:.85},dry:{toward:"#e9edf0",weight:.8},flowers:{toward:"#ffffff",weight:1}}},scrub:{spring:{ground:{tint:[.96,1.05,.92]},bushes:{tint:[.7,.86,.66]}},summer:{bushes:{tint:[.68,.8,.64]}},autumn:{ground:{tint:[1.05,.98,.84]},bushes:{tint:[.86,.74,.56],toward:"#8a5a2e",weight:.25}},winter:{ground:{tint:[1,.96,.88],toward:"#a59e8c",weight:.25},bushes:{tint:[.7,.68,.62]}},snow:{ground:{toward:SNOW,weight:.85},bushes:{tint:[.66,.66,.62],toward:"#d8dcdf",weight:.3}}},farmland:{spring:{ground:{tint:[.97,1.02,.94]},young:{tint:[.82,1.06,.74]},cereal:{tint:[.88,1.05,.78]},soil:{tint:[.9,.8,.7]},pasture:{tint:[.88,1.07,.84]},rapeseed:{tint:[1.1,1.08,.6],toward:"#efd83c",weight:.45},stubble:{tint:[.93,.86,.76]},hedges:{tint:[.74,.9,.66]}},summer:{young:{tint:[.85,1,.8]},cereal:{tint:[1.09,1.04,.78]},soil:{tint:[.97,.88,.77]},pasture:{tint:[.92,1.03,.89]},rapeseed:{tint:[1.08,1.07,.72]},stubble:{tint:[1.05,.99,.86]},hedges:{tint:[.7,.82,.66]}},autumn:{ground:{tint:[1.03,.98,.88]},young:{tint:[.9,.99,.82]},cereal:{tint:[1.07,1,.8]},soil:{tint:[.92,.82,.7]},pasture:{tint:[.98,1,.86]},rapeseed:{tint:[.95,.88,.76]},stubble:{tint:[1.08,.99,.82]},hedges:{tint:[.92,.78,.6],toward:"#a8662f",weight:.3}},winter:{ground:{tint:[.98,.94,.88]},young:{tint:[.88,.97,.84]},cereal:{tint:[.94,.86,.76]},soil:{tint:[.9,.82,.72]},pasture:{tint:[.96,.98,.9]},rapeseed:{tint:[.86,.98,.82]},stubble:{tint:[1,.94,.84]},hedges:{tint:[.78,.74,.68]}},snow:{ground:{toward:SNOW,weight:.88},young:{toward:SNOW,weight:.85},cereal:{toward:SNOW,weight:.86},soil:{tint:[.9,.82,.72],toward:"#e8ecef",weight:.55},pasture:{toward:SNOW,weight:.86},rapeseed:{toward:SNOW,weight:.8},stubble:{toward:SNOW,weight:.82},hedges:{tint:[.7,.68,.64],toward:"#d8dcdf",weight:.3}}},sand:{spring:{wet:{tint:[.74,.72,.69]}},summer:{wet:{tint:[.74,.72,.69]}},autumn:{ground:{tint:[.98,.97,.95]},wet:{tint:[.72,.7,.68]}},winter:{ground:{tint:[.95,.95,.94]},wet:{tint:[.7,.69,.68]}},snow:{ground:{toward:SNOW,weight:.7},wet:{tint:[.7,.69,.68]}}},mud:{spring:{ground:{tint:[.92,.9,.86]},wet:{tint:[.66,.66,.68]}},summer:{ground:{tint:[.94,.91,.86]},wet:{tint:[.68,.67,.68]}},autumn:{ground:{tint:[.9,.88,.84]},wet:{tint:[.64,.64,.66]}},winter:{ground:{tint:[.88,.88,.88]},wet:{tint:[.62,.64,.68]}},snow:{ground:{toward:SNOW,weight:.5},wet:{tint:[.7,.72,.76]}}},gravel:{spring:{},summer:{},autumn:{},winter:{ground:{tint:[.95,.96,.98]}},snow:{ground:{toward:SNOW,weight:.6}}},rock:{spring:{},summer:{},autumn:{},winter:{ground:{tint:[.95,.96,.98]}},snow:{ground:{toward:SNOW,weight:.65}}},paving:{spring:{joints:{tint:[.8,.8,.82]}},summer:{joints:{tint:[.8,.8,.82]}},autumn:{ground:{tint:[.97,.97,.97]},joints:{tint:[.78,.78,.8]}},winter:{ground:{tint:[.94,.95,.97]},joints:{tint:[.78,.78,.8]}},snow:{ground:{toward:"#e6eaee",weight:.4},joints:{tint:[.85,.86,.88]}}},urban:{spring:{},summer:{},autumn:{},winter:{ground:{tint:[.96,.97,.98]}},snow:{ground:{toward:SNOW,weight:.45}}},roads:{spring:{},summer:{},autumn:{ground:{tint:[.97,.97,.97]}},winter:{ground:{tint:[.92,.93,.95]}},snow:{ground:{toward:"#e6eaee",weight:.35}}},trees:{spring:{broadleaf:{tint:[1.04,1.12,.84],toward:"#a9d465",weight:.2},conifer:{tint:[.8,.92,.88]}},summer:{conifer:{tint:[.78,.88,.9]}},autumn:{broadleaf:{tint:[1.12,.9,.62],toward:"#cf7a2e",weight:.45},conifer:{tint:[.78,.86,.86]}},winter:{broadleaf:{toward:"#7f776d",weight:.7},conifer:{tint:[.74,.84,.86]}},snow:{broadleaf:{toward:"#d3d8dc",weight:.65},conifer:{tint:[.72,.82,.84],toward:SNOW,weight:.3}}}},TREE_VARIETY={spring:.25,summer:0,autumn:1,winter:0,snow:0},BLACK=[0,0,0],rgbOf=e=>{const[t,o,r]=parsedCssColor(e)??BLACK;return[t,o,r]},shadeUniformOf=({tint:e=[1,1,1],toward:t,weight:o=0})=>({tint:e,toward:[...t?rgbOf(t):BLACK,o]}),MATERIAL_ROLES=/* @__PURE__ */(()=>surfaceKinds.flatMap(e=>PALETTE_ROLES[e].map(t=>({kind:e,role:t}))))(),paletteRolesGlsl=()=>{const e=new Array(SURFACE_ID_COUNT).fill(0),t=MATERIAL_ROLES.map(({kind:t,role:o},r)=>("ground"===o&&(e[SURFACE_IDS[t]]=r),`const int ${t.toUpperCase()}_${o.toUpperCase()} = ${r};`));return[`const int ROLE_COUNT = ${MATERIAL_ROLES.length};`,...t,`const int GROUND_ROLES[SURFACE_ID_COUNT] = int[SURFACE_ID_COUNT](${e.join(", ")});`].join("\n")},treePlaced_default="uniform highp sampler2D u_placement;struct Tree{float height;int stand;int species;ivec2 cell;ivec2 slot;vec2 position;};Tree placedTree(){ivec2 cell=ivec2(gl_InstanceID%GRID,gl_InstanceID/GRID);vec4 placed=round(texelFetch(u_placement,u_tile_slot+cell,0)*255.);Tree tree=Tree(0.,0,0,cell,ivec2(0),vec2(0.));tree.height=placed.b>0.?(placed.b-1.)/254.*MAX_HEIGHT:0.;if(tree.height<=0.)return tree;tree.stand=int(placed.a)>>4;tree.species=int(placed.a)&15;tree.slot=(u_tile.xy*GRID+cell)*(1<<(FINEST-u_tile.z))+ivec2(placed.rg);tree.position=slotPosition(tree.slot,u_tile,STAND_ROWS[tree.stand]>.5,slotRandoms(tree.slot,0u));return tree;}const vec4 LEFT_OUT=vec4(2.,2.,2.,1.);\n",treeStands=["forest","park","garden","meadow","scrub","heath","orchard","cemetery","playground"],treeSpecies=["broadleaf","conifer","bush","columnar","umbrella"],SPECIES_SHAPES={broadleaf:{crownHeight:.62,crownRadius:.34,heightFactor:1,needles:!1},conifer:{crownHeight:.55,crownRadius:.22,heightFactor:1.15,needles:!0},bush:{crownHeight:.5,crownRadius:.45,heightFactor:1,needles:!1},columnar:{crownHeight:.6,crownRadius:.14,heightFactor:1.2,needles:!1},umbrella:{crownHeight:.86,crownRadius:.48,heightFactor:.9,needles:!0}},TREE_MASK_IDS={clear:0,forest:1,park:2,garden:3,meadow:4,scrub:5,heath:6,orchard:7,cemetery:8,playground:9,track:15},STAND_TRAITS={forest:{density:.9,heightMeters:13.5,groves:.3,shares:{conifer:"latitude",bush:.06,columnar:.02,umbrella:.35},rows:!1,wild:!0},park:{density:.08,heightMeters:12,groves:.9,shares:{conifer:.12,bush:.18,columnar:.08,umbrella:.35},rows:!1,wild:!1},garden:{density:.1,heightMeters:6.5,groves:.35,shares:{conifer:.25,bush:.45,columnar:.1,umbrella:.15},rows:!1,wild:!1},meadow:{density:.02,heightMeters:10.5,groves:.6,shares:{conifer:.2,bush:.35,columnar:.08,umbrella:.3},rows:!1,wild:!0},scrub:{density:.5,heightMeters:4,groves:.45,shares:{conifer:.1,bush:.85,umbrella:.15},rows:!1,wild:!0},heath:{density:.22,heightMeters:2.5,groves:.5,shares:{conifer:.35,bush:.95,umbrella:.1},rows:!1,wild:!0},orchard:{density:.95,heightMeters:4,groves:0,shares:{conifer:0},rows:!0,wild:!1},cemetery:{density:.3,heightMeters:9.5,groves:.3,shares:{conifer:.5,bush:.2,columnar:.35,umbrella:.2},rows:!1,wild:!1},playground:{density:.07,heightMeters:10.5,groves:.5,shares:{conifer:.1,bush:.2,columnar:.05,umbrella:.2},rows:!1,wild:!1}},tagIn=e=>["match",["get","primary_tag"],e,!0,!1],PLAYGROUND_TAGS=["lsr:playground","lsr:dog_park"],STAND_TARGETS=/* @__PURE__ */(()=>[{layerId:STYLE_LAYER_IDS.landuse,classes:{park:tagIn(["lsr:park","lds:recreation_ground","lds:village_green"]),cemetery:["any",["==",["get","category"],"cemetery"],tagIn(["lds:cemetery","amn:grave_yard"])]}},{layerId:STYLE_LAYER_IDS.landcover,classes:{orchard:tagIn(["lds:orchard"]),clear:["any",["==",["get","wetland"],!0],["match",["get","category"],["agricultural","sandy","bareland"],!0,!1],tagIn(["lds:flowerbed"])],forest:["==",["get","category"],"woodland"],scrub:tagIn(["ntr:scrub","ntr:shrubbery"]),heath:tagIn(["ntr:heath"]),meadow:tagIn(["lds:meadow","ntr:grassland"]),garden:tagIn(["lsr:garden","lds:allotments"])}},{layerId:STYLE_LAYER_IDS.outdoorAndSport,classes:{playground:tagIn(PLAYGROUND_TAGS),clear:["!",tagIn(PLAYGROUND_TAGS)]}},{layerId:STYLE_LAYER_IDS.water,classes:{clear:!0}},{layerId:STYLE_LAYER_IDS.intermittentWater,classes:{clear:!0}},{layerId:STYLE_LAYER_IDS.buildings,classes:{clear:!0}}])(),CLEARING_LINE_SOURCES=/* @__PURE__ */new Set(["roads","transit","water_lines"]),isClearingLine=e=>"line"===e.type&&CLEARING_LINE_SOURCES.has(e["source-layer"]??"")&&!e.id.startsWith("Tunnel"),floatArrayGlsl=e=>`float[${e.length}](${e.map(e=>e.toFixed(4)).join(", ")})`,standTraitsGlsl=()=>{const e=treeStands.length+1,t=t=>{const o=new Array(e).fill(0);for(const e of treeStands)o[TREE_MASK_IDS[e]]=t(STAND_TRAITS[e]);return floatArrayGlsl(o)},o=e=>t(({shares:t})=>{const o=t[e];return"latitude"===o?-1:o??0}),r=treeSpecies.map(e=>SPECIES_SHAPES[e]);return[`const int STAND_COUNT = ${e};`,`const float STAND_DENSITY[STAND_COUNT] = ${t(({density:e})=>e)};`,`const float STAND_HEIGHT[STAND_COUNT] = ${t(({heightMeters:e})=>e)};`,`const float STAND_CONIFERS[STAND_COUNT] = ${o("conifer")};`,`const float STAND_GROVES[STAND_COUNT] = ${t(({groves:e})=>e)};`,`const float STAND_BUSHES[STAND_COUNT] = ${o("bush")};`,`const float STAND_COLUMNAR[STAND_COUNT] = ${o("columnar")};`,`const float STAND_UMBRELLA[STAND_COUNT] = ${o("umbrella")};`,`const float STAND_ROWS[STAND_COUNT] = ${t(({rows:e})=>e?1:0)};`,`const float STAND_WILD[STAND_COUNT] = ${t(({wild:e})=>e?1:0)};`,...treeStands.map(e=>`const int ${e.toUpperCase()}_STAND = ${TREE_MASK_IDS[e]};`),`const int TRACK_KEY = ${TREE_MASK_IDS.track};`,`const int SPECIES_COUNT = ${treeSpecies.length};`,...treeSpecies.map((e,t)=>`const int ${e.toUpperCase()} = ${t};`),`const float SPECIES_CROWN_HEIGHT[SPECIES_COUNT] = ${floatArrayGlsl(r.map(({crownHeight:e})=>e))};`,`const float SPECIES_CROWN_RADIUS[SPECIES_COUNT] = ${floatArrayGlsl(r.map(({crownRadius:e})=>e))};`,`const float SPECIES_HEIGHT_FACTOR[SPECIES_COUNT] = ${floatArrayGlsl(r.map(({heightFactor:e})=>e))};`,`const float SPECIES_NEEDLES[SPECIES_COUNT] = ${floatArrayGlsl(r.map(({needles:e})=>e?1:0))};`].join("\n")},THEMED_DEFAULTS={light:{"light.direction":THEMED_LIGHTS_light_direction,"light.altitude":THEMED_LIGHTS_light_altitude,"surfaces.water.glint.color":"#fff6e0","sky.color":"#6ea6d8","sky.horizonColor":"#e4eef5"},dark:{"light.direction":THEMED_LIGHTS_dark_direction,"light.altitude":THEMED_LIGHTS_dark_altitude,"surfaces.water.glint.color":"#64708a","sky.color":"#0a1220","sky.horizonColor":"#26344a"}},contextValueOf=(e,{theme:t,sky:o,light:r})=>{const a=THEMED_DEFAULTS[t];switch(e){case"light.direction":case"light.altitude":return r?lightKnobsOf(r)[e]:a[e];case"surfaces.water.glint.color":return a[e];case"sky.color":return o.color??a[e];case"sky.horizonColor":return o.horizonColor??a[e];default:return}},THEMED_TREES={light:{wild:"hsl(110, 45%, 75%)",tended:"hsl(110, 48%, 77%)",shadowsIntensity:1},dark:{wild:"hsl(175, 30%, 18%)",tended:"hsl(175, 30%, 20%)",shadowsIntensity:.6}},knobIdOf=(e,t)=>`${"trees"===e?"trees":`surfaces.${e}`}.${t}`,firstSeasonIn=(e,t)=>t.map(t=>knobValueIn(e,t)).find(isSurfaceSeason)??"summer",seasonIn=(e,t)=>firstSeasonIn(e,[knobIdOf(t,"season"),"season"]),partShadeOf=(e,t,o,r)=>((e,t,o,r)=>r?{toward:r,weight:1}:PALETTES[e][t][o]??{})(e,t,o,r),derivedColorOf=(e,t,o)=>{const[r,a]=(e=>{const[t,o]=e.split(".colors.");return[surfaceKinds.find(e=>t===`surfaces.${e}`)??"trees",o]})(e),i=((e,{theme:t,foliage:o,surfaceColors:r})=>"trees"!==e?r?.[e]:o?.wild||o?.tended?o.wild??THEMED_TREES[t].wild:void 0)(r,o);if(!i)return;const s=partShadeOf(r,seasonIn(t,r),a);return n=((e,t)=>{const{tint:o,toward:r}=shadeUniformOf(t);return e.map((e,t)=>{const a=e*o[t];return MathUtils.clamp(a+(r[t]-a)*r[3],0,1)})})(rgbOf(i),s),`#${n.map(e=>Math.round(255*e).toString(16).padStart(2,"0")).join("")}`;var n},resolveSurfacesLook=(e,t)=>Object.fromEntries(glSurfacesKnobCatalogue.map(({id:o,default:r})=>{if("season"===o||o.endsWith(".season"))return[o,firstSeasonIn(e,[o,"season"])];const a=knobValueIn(e,o);return void 0!==a?[o,a]:(e=>e.includes(".colors."))(o)?[o,derivedColorOf(o,e,t)]:[o,contextValueOf(o,t)??r]})),PATTERN_KNOBS={water:["surfaces.water.waves.heightFactor","surfaces.water.enclosed.waves.heightFactor","surfaces.water.shore.intensity","surfaces.water.shore.reachMeters"],ice:["surfaces.ice.crevasses.intensity"],forest:["surfaces.forest.crowns.sizeFactor","surfaces.forest.conifer.fraction"],grass:["surfaces.grass.mown.fraction","surfaces.grass.stripes.intensity","surfaces.grass.flowers.fraction"],scrub:["surfaces.scrub.bushes.intensity"],farmland:["surfaces.farmland.parcels.sizeFactor","surfaces.farmland.rows.intensity","surfaces.farmland.hedges.intensity"],sand:["surfaces.sand.dunes.intensity","surfaces.sand.ripples.intensity","surfaces.sand.wet.widthMeters"],mud:["surfaces.mud.puddles.intensity"],gravel:["surfaces.gravel.stones.intensity"],rock:["surfaces.rock.ridges.intensity"],paving:["surfaces.paving.joints.intensity"],urban:["surfaces.urban.wear.intensity"],roads:["surfaces.roads.wear.intensity"]},towardsSunOf=(e,t)=>{const[o,r,a]=towardsLightOf(e,t);return[o,-r,a]},shadeUniformIn=(e,t,o)=>shadeUniformOf(partShadeOf(t,seasonIn(e,t),o,((e,t,o)=>{const r=knobValueIn(e,knobIdOf(t,`colors.${o}`));return"string"==typeof r?r:void 0})(e,t,o))),patternsOf=e=>Object.fromEntries(surfaceKinds.map(t=>{const o=PATTERN_KNOBS[t].map(t=>"surfaces.forest.crowns.sizeFactor"===t?8*e[t]:e[t]);return[t,o.length>1?o:o[0]]})),surfaceUniformsOf=(e,t)=>{const o=resolveSurfacesLook(e,t),{theme:r,foliage:a}=t,i=THEMED_TREES[r],s=MathUtils.degToRad(o["wind.direction"]);return{intensities:Object.fromEntries(surfaceKinds.map(e=>[e,o.visible?o[`surfaces.${e}.intensity`]:0])),sun:towardsSunOf(o["light.direction"],o["light.altitude"]),glintColor:rgbOf(o["surfaces.water.glint.color"]),skyColor:rgbOf(o["sky.color"]),horizonColor:rgbOf(o["sky.horizonColor"]),reflection:o["surfaces.water.reflection.intensity"],glint:o["surfaces.water.glint.intensity"],wind:[-Math.sin(s),Math.cos(s)],windSpeedFactor:o["wind.speedFactor"],trees:{visible:o.visible&&o["trees.visible"],densityFactor:o["trees.densityFactor"],sizeFactor:o["trees.sizeFactor"],minZoom:o["trees.minZoom"],shareFactors:treeSpecies.map(e=>o[`trees.species.${e}.shareFactor`]),tracksIntensity:o.visible&&o["trees.visible"]?o["trees.tracks.intensity"]:0,shadowsIntensity:o["trees.shadows.intensity"]*i.shadowsIntensity,foliage:{wild:rgbOf(a?.wild??i.wild),tended:rgbOf(a?.tended??i.tended)},foliageFromGround:!a?.wild&&!a?.tended,sunColor:rgbOf(THEMED_SUN_COLORS[r]),broadleaf:shadeUniformIn(e,"trees","broadleaf"),conifer:shadeUniformIn(e,"trees","conifer"),variety:TREE_VARIETY[seasonIn(e,"trees")]},shades:MATERIAL_ROLES.map(({kind:t,role:o})=>shadeUniformIn(e,t,o)),patterns:patternsOf(o)}},PLACEMENT_COLUMNS=/* @__PURE__ */Math.ceil(/* @__PURE__ */Math.sqrt(256)),PLACEMENT_SIZE=32*PLACEMENT_COLUMNS,MOVING_EASE=[.2,.1],SETTLING_EASE=[.5,.5],FINAL_EASE=[1,1],NO_SLOT=[-1,-1],tileKeyOf=(e,t,o,r)=>`${e}/${t}/${o}/${r}`,tileUniforms=()=>({...tileGroundUniforms(),...uniformsHolding({u_tile:[0,0,0],u_tile_slot:[0,0],u_tile_scale:0,u_tile_camera:[0,0],u_camera_altitude:0})}),intoMercator=/* @__PURE__ */new Matrix4,ontoShadowMap=/* @__PURE__ */new Matrix4,SAME_SUN=/* @__PURE__ */Math.cos(/* @__PURE__ */MathUtils.degToRad(4)),groundOf=(e,t)=>{if(!e.terrain)return{elevation:0,relief:0};const o=e.getCenter();return{elevation:MercatorCoordinate.fromLngLat(o,t).z,relief:MercatorCoordinate.fromLngLat(o,2e3*e.terrain.exaggeration).z}},instancedTreesOf=({vertices:e,indices:t})=>{const o=new InstancedBufferGeometry,r=new InterleavedBuffer(e,TREE_VERTEX_FLOATS);let a=0;for(const{name:i,size:s}of TREE_VERTEX_LAYOUT)o.setAttribute(i,new InterleavedBufferAttribute(r,s,a)),a+=s;return o.setIndex(new BufferAttribute(t,1)),o.instanceCount=1024,o},treeChunks=()=>[standTraitsGlsl(),"uniform ivec3 u_tile;uniform ivec2 u_tile_slot;uniform float u_tile_scale;uniform vec2 u_tile_camera;uniform float u_camera_altitude;ivec2 quadrantOf(ivec2 block,int level){uint q=hashOf(uvec2(block)+uvec2(uint(level)*0x9E3779B9u,uint(level)*0x7F4A7C15u))&3u;return ivec2(int(q&1u),int(q>>1u));}ivec2 finestSlotOf(ivec2 block,int level){for(int l=level;l<FINEST;l++)block=block*2+quadrantOf(block,l);return block;}int coarsestLevelOf(ivec2 block,int level){int coarsest=level;for(int l=level-1;l>=max(level-6,0);l--){ivec2 parent=block>>1;if(quadrantOf(parent,l)!=(block&1))break;block=parent;coarsest=l;}return coarsest;}vec4 slotRandoms(ivec2 slot,uint salt){uint a=hashOf(uvec2(slot)^uvec2(salt,salt*0x68E31DA4u));uint b=hashOf(uvec2(a,salt+0xB5297A4Du));return vec4(halvesOf(a),halvesOf(b));}vec2 slotPosition(ivec2 slot,ivec3 tile,bool rows,vec4 randoms){int span=1<<(FINEST-tile.z);vec2 local=vec2(slot-tile.xy*GRID*span);vec2 jitter=rows?vec2(0.):(randoms.xy-.5)*.9;return(local+.5+jitter)*(EXTENT/float(GRID*span));}\n"],placementMaterialOf=e=>rawMaterial({name:"trees placement",vertexShader:vertexSourceOf(e,...treeChunks(),"uniform sampler2D u_before;uniform sampler2D u_mask;uniform sampler2D u_previous;uniform sampler2D u_previous_ground;uniform ivec2 u_previous_slot;uniform ivec2 u_previous_parent_slot;uniform ivec2 u_previous_child_slots[4];uniform float u_keep_stands;uniform vec2 u_ease;uniform vec2 u_viewport;uniform vec2 u_placement_size;uniform float u_lod;uniform float u_pixel_angle;uniform float u_density_factor;uniform float u_size_factor;uniform float u_growth;uniform float u_wild_conifers;uniform float u_warm_climate;uniform float u_treeline;uniform float u_share_factors[SPECIES_COUNT];uniform bool u_ground_follows;flat out vec4 v_placement;flat out vec4 v_ground;float footElevation=0.;vec4 projectGround(vec2 position){return projectTileWithElevation(position,footElevation);}float slotNoise(ivec2 slot,int shift,uint salt){ivec2 cell=slot>>shift;vec2 f=vec2(slot-(cell<<shift))/float(1<<shift);f=f*f*(3.-2.*f);float a=slotRandoms(cell,salt).x;float b=slotRandoms(cell+ivec2(1,0),salt).x;float c=slotRandoms(cell+ivec2(0,1),salt).x;float d=slotRandoms(cell+ivec2(1,1),salt).x;return mix(mix(a,b,f.x),mix(c,d,f.x),f.y);}vec2 pixelOf(vec4 clip){return(clip.xy/clip.w*.5+.5)*u_viewport;}ivec2 texelOf(vec4 clip){return ivec2(clamp(pixelOf(clip),vec2(0.),u_viewport-1.));}int standAt(ivec2 texel){vec3 mask=texelFetch(u_mask,texel,0).rgb;vec3 before=texelFetch(u_before,texel,0).rgb;if(mask.g<.98||mask.b>.02||all(lessThan(abs(mask-before),vec3(.003))))return-1;float red=mask.r*255.;float key=floor(red/16.);return abs(red-key*16.-8.)<2.5?int(key):-1;}int standAtGround(vec2 position,int unseen){vec4 clip=projectGround(position);if(clip.w<=0.)return unseen;vec2 pixel=pixelOf(clip);if(any(lessThan(pixel,vec2(0.)))||any(greaterThanEqual(pixel,u_viewport)))return unseen;return standAt(ivec2(pixel));}float clearanceOf(vec2 position,int stand,float radius,float pixels){int steps=clamp(int(ceil(pixels/1.5)),2,16);float clearance=1.;for(int way=0;way<8;way++){float angle=float(way)*TAU/8.+.2;vec2 outward=vec2(cos(angle),sin(angle))*radius;for(int step=1;step<=steps;step++){float reach=float(step)/float(steps);if(reach>=clearance)break;if(standAtGround(position+outward*reach,stand)==stand)continue;if(standAtGround(position+outward*(reach+.6),-2)==stand)clearance=reach-1./float(steps);break;}}return clearance;}vec4 previousPlacement=vec4(0.);bool fadingOut=false;ivec2 previousTexel=ivec2(-1);void findPrevious(ivec2 cell){ivec2 block=u_tile.xy*GRID+cell;if(u_previous_slot.x>=0){previousTexel=u_previous_slot+cell;previousPlacement=texelFetch(u_previous,previousTexel,0);return;}int level=u_tile.z-1;ivec2 levelBlock=block>>1;ivec2 levelTile=u_tile.xy>>1;ivec2 corner=u_previous_parent_slot;if(corner.x<0){level=u_tile.z+1;levelBlock=block*2+quadrantOf(block,u_tile.z);levelTile=levelBlock/GRID;ivec2 child=levelTile-u_tile.xy*2;corner=u_previous_child_slots[child.x+child.y*2];}if(corner.x<0)return;ivec2 texel=corner+levelBlock-levelTile*GRID;vec4 previous=texelFetch(u_previous,texel,0);ivec2 slot=finestSlotOf(block,u_tile.z);if(previous.b<=0.||levelBlock*(1<<(FINEST-level))+ivec2(round(previous.rg*255.))!=slot)return;previousTexel=texel;previousPlacement=vec4(vec2(slot-block*(1<<(FINEST-u_tile.z)))/255.,previous.ba);}void placeTree(ivec2 cell){ivec2 block=u_tile.xy*GRID+cell;ivec2 slot=finestSlotOf(block,u_tile.z);vec4 randoms=slotRandoms(slot,0u);vec2 position=slotPosition(slot,u_tile,false,randoms);footElevation=groundElevationAt(position);vec4 clip=projectGround(position);if(clip.w<=0.)return;int jitteredStand=standAt(texelOf(clip));bool rows=jitteredStand>0&&jitteredStand<STAND_COUNT&&STAND_ROWS[jitteredStand]>.5;if(rows){position=slotPosition(slot,u_tile,true,randoms);footElevation=groundElevationAt(position);clip=projectGround(position);if(clip.w<=0.)return;}vec2 foot=pixelOf(clip);ivec2 footTexel=texelOf(clip);int stands[9];stands[0]=standAt(footTexel);for(int index=1;index<9;index++){float angle=float(index)*TAU/8.;vec2 pixel=clamp(foot+1.5*vec2(cos(angle),sin(angle)),vec2(0.),u_viewport-1.);stands[index]=standAt(ivec2(pixel));}if(stands[0]==0||stands[0]>=STAND_COUNT)return;int stand=stands[0];for(int index=1;index<9&&stand<=0;index++)stand=stands[index];int stood=previousPlacement.b>0.?int(round(previousPlacement.a*255.))/16:0;for(int index=1;index<9&&stood>0&&stand!=stood;index++){if(stands[index]==stood)stand=stood;}if(stand<=0||stand>=STAND_COUNT||(STAND_ROWS[stand]>.5)!=rows)return;bool kept=stood==stand;float covered=stands[0]==stand?.2:0.;for(int index=1;index<9;index++)covered+=stands[index]==stand?.1:0.;if(covered<(kept?.35:.55))return;vec3 before=texelFetch(u_before,footTexel,0).rgb;float altitude=u_dem_exaggeration>0.?footElevation/u_dem_exaggeration:0.;float uphill=STAND_CONIFERS[stand]<0.?smoothstep(.45,.85,altitude/u_treeline):0.;float belowTreeline=STAND_CONIFERS[stand]<0.?1.-smoothstep(.9,1.05,altitude/u_treeline):1.;float groves=mix(1.,2.2*smoothstep(.3,.75,slotNoise(slot,3,11u)),STAND_GROVES[stand]);if(randoms.z>=STAND_DENSITY[stand]*u_density_factor*groves*belowTreeline)return;vec2 relative=u_tile_camera+position*u_tile_scale;float distance=length(vec3(relative,u_camera_altitude-footElevation));float shown=clamp(u_lod-log2(distance)-float(coarsestLevelOf(block,u_tile.z)),0.,1.);if(shown<=.25+.7*randoms.w-(kept?.1:0.)){fadingOut=true;return;}float conifers=STAND_CONIFERS[stand]<0.?mix(u_wild_conifers,.9,uphill):STAND_CONIFERS[stand];conifers=clamp(conifers+(slotNoise(slot,4,23u)-.5)*min(1.4,conifers*3.+.2),0.,1.);float umbrellas=STAND_UMBRELLA[stand]*u_warm_climate;if(umbrellas>0.){umbrellas=clamp(umbrellas+(slotNoise(slot,4,29u)-.5)*min(1.4,umbrellas*3.),0.,1.);}float columnar=STAND_COLUMNAR[stand];float trees=1.-STAND_BUSHES[stand];float shares[SPECIES_COUNT];shares[CONIFER]=trees*conifers;shares[UMBRELLA]=trees*(1.-conifers)*umbrellas;shares[COLUMNAR]=trees*(1.-conifers)*(1.-umbrellas)*columnar;shares[BROADLEAF]=trees*(1.-conifers)*(1.-umbrellas)*(1.-columnar);shares[BUSH]=STAND_BUSHES[stand];float total=0.;for(int index=0;index<SPECIES_COUNT;index++){shares[index]*=u_share_factors[index];total+=shares[index];}if(total<=0.)return;vec4 kind=slotRandoms(slot,1u);int species=BROADLEAF;float pick=kind.x*total;for(int index=0;index<SPECIES_COUNT;index++){if(shares[index]<=0.)continue;species=index;if(pick<shares[index])break;pick-=shares[index];}float height=STAND_HEIGHT[stand];if(species==BUSH)height=min(height,2.1)*mix(.55,1.1,kind.z);else height*=(STAND_ROWS[stand]>.5?mix(.9,1.1,kind.z):mix(.65,1.3,kind.z))*SPECIES_HEIGHT_FACTOR[species];height*=u_size_factor*u_growth*mix(.5,1.,belowTreeline);if(height/(distance*u_pixel_angle)<(kept?1.:1.5))return;float crown=1.25*SPECIES_CROWN_RADIUS[species]*height;float crownPixels=crown/(distance*u_pixel_angle);if(crownPixels>3.&&clearanceOf(position,stand,crown/u_tile_scale,crownPixels)<(kept?.4:.65))return;ivec2 offset=slot-block*(1<<(FINEST-u_tile.z));float encodedHeight=1.+round(clamp(height/MAX_HEIGHT,0.,1.)*254.);v_placement=vec4(float(offset.x),float(offset.y),encodedHeight,float(stand*16+species))/255.;bool standing=kept&&previousTexel.x>=0;if(standing&&!u_ground_follows){v_ground=texelFetch(u_previous_ground,previousTexel,0);return;}float reach=height*.25/u_tile_scale;vec3 ground=vec3(0.);float weights=0.;for(int index=0;index<5;index++){float angle=float(index)*TAU/4.+.4;vec4 around=index==0?clip:projectGround(position+reach*vec2(cos(angle),sin(angle)));vec3 seen=around.w>0.?texelFetch(u_before,texelOf(around),0).rgb:before;float weight=(1.+3.*max(seen.g-max(seen.r,seen.b),0.))/(.35+luminanceOf(seen));ground+=weight*seen;weights+=weight;}ground/=weights;if(standing)ground=mix(texelFetch(u_previous_ground,previousTexel,0).rgb,ground,.15);v_ground=vec4(ground,1.);}const float GRACE_PLACEMENTS=8.;const float FADE_OUT_EASE=.3;float easedHeight(float from,float to,float shrinking){float step=(to-from)*(to>from?u_ease.x:shrinking);return from+(step>0.?ceil(step):floor(step));}void main(){ivec2 cell=ivec2(gl_VertexID%GRID,gl_VertexID/GRID);gl_Position=vec4((vec2(u_tile_slot+cell)+.5)/u_placement_size*2.-1.,0.,1.);gl_PointSize=1.;v_placement=vec4(0.);v_ground=vec4(0.);findPrevious(cell);placeTree(cell);float before=previousPlacement.b>0.?round(previousPlacement.b*255.)-1.:0.;if(v_placement.b>0.){v_placement.b=(easedHeight(before,round(v_placement.b*255.)-1.,u_ease.y)+1.)/255.;v_ground.a=GRACE_PLACEMENTS/255.;return;}if(before<=0.)return;vec4 previousGround=texelFetch(u_previous_ground,previousTexel,0);float grace=round(previousGround.a*255.)-1.;if(u_keep_stands>.5&&grace>=0.&&!fadingOut){v_placement=previousPlacement;v_ground=vec4(previousGround.rgb,grace/255.);}else{float shrunk=easedHeight(before,0.,fadingOut?max(u_ease.y,FADE_OUT_EASE):u_ease.y);v_placement=shrunk>0.?vec4(previousPlacement.rg,(shrunk+1.)/255.,previousPlacement.a):vec4(0.);v_ground=shrunk>0.?vec4(previousGround.rgb,0.):vec4(0.);}}\n"),fragmentShader:"precision highp float;flat in vec4 v_placement;flat in vec4 v_ground;layout(location=0)out vec4 placement;layout(location=1)out vec4 ground;void main(){placement=v_placement;ground=v_ground;}\n",uniforms:{...tileUniforms(),...uniformsHolding({u_before:null,u_mask:null,u_previous:null,u_previous_ground:null,u_previous_slot:NO_SLOT,u_previous_parent_slot:NO_SLOT,u_previous_child_slots:/* @__PURE__ */new Int32Array(8),u_keep_stands:0,u_ease:FINAL_EASE,u_viewport:[0,0],u_placement_size:[PLACEMENT_SIZE,PLACEMENT_SIZE],u_lod:0,u_pixel_angle:0,u_density_factor:0,u_size_factor:0,u_growth:0,u_wild_conifers:0,u_warm_climate:0,u_treeline:0,u_share_factors:[],u_ground_follows:!1})}}),shadowsMaterialOf=e=>rawMaterial({name:"trees shadows",vertexShader:vertexSourceOf(e,...treeChunks(),treePlaced_default,"uniform vec3 u_sun;uniform float u_shadows_intensity;out vec2 v_ground;flat out vec4 v_shadow;flat out float v_foot;void main(){Tree tree=placedTree();if(tree.height<=0.||u_shadows_intensity<=0.){gl_Position=LEFT_OUT;return;}float crownHeight=SPECIES_CROWN_HEIGHT[tree.species];float crownRadius=SPECIES_CROWN_RADIUS[tree.species];float reach=min(length(u_sun.xy)/max(u_sun.z,.05),3.);vec2 away=-normalize(u_sun.xy+vec2(1e-5));float center=crownHeight*reach*tree.height;vec2 halfAxes=vec2(crownRadius+.3*reach,crownRadius)*tree.height;float foot=crownRadius*.7*tree.height;int quadCorner=int[6](0,1,2,2,1,3)[gl_VertexID];vec2 corner=vec2(quadCorner&1,quadCorner>>1);vec2 ground=vec2(mix(min(-foot,center-halfAxes.x),center+halfAxes.x,corner.x),mix(-1.,1.,corner.y)*max(halfAxes.y,foot));vec2 offset=away*ground.x+vec2(-away.y,away.x)*ground.y;vec2 position=tree.position+offset/u_tile_scale;float lift=u_dem_exaggeration>0.?1.5:0.;gl_Position=projectTileOnGround(position,groundElevationAt(position)+lift);v_ground=ground;v_shadow=vec4(center,halfAxes,u_shadows_intensity*(tree.species==BUSH?.7:1.));v_foot=foot;}\n"),fragmentShader:"precision highp float;uniform sampler2D u_before;in vec2 v_ground;flat in vec4 v_shadow;flat in float v_foot;out vec4 fragColor;void main(){float crown=1.-smoothstep(.3,1.,length((v_ground-vec2(v_shadow.x,0.))/v_shadow.yz));float foot=1.-smoothstep(0.,v_foot,length(v_ground));float shade=max(crown,foot*.7)*v_shadow.w;if(shade<=.004)discard;vec3 before=texelFetch(u_before,ivec2(gl_FragCoord.xy),0).rgb;fragColor=vec4(before*mix(vec3(1.),vec3(.5,.54,.62),shade),1.);}\n",uniforms:{...tileUniforms(),...uniformsHolding({u_placement:null,u_before:null,u_sun:[0,0,0],u_shadows_intensity:0})},blending:CustomBlending,blendEquation:MinEquation,depthFunc:LessEqualDepth}),treesMaterialOf=e=>rawMaterial({name:"trees",vertexShader:vertexSourceOf(e,...treeChunks(),treePlaced_default,"in vec3 a_position;in vec3 a_normal;in vec3 a_center;in vec3 a_info;uniform vec2 u_wind;uniform float u_wind_clock;uniform float u_pixel_angle;uniform vec3 u_foliage_wild;uniform vec3 u_foliage_tended;uniform bool u_foliage_from_ground;uniform vec3 u_broadleaf_tint;uniform vec4 u_broadleaf_toward;uniform vec3 u_conifer_tint;uniform vec4 u_conifer_toward;uniform float u_foliage_variety;uniform highp sampler2D u_placement_ground;uniform mat4 u_tile_to_shadow;out vec3 v_normal;out vec3 v_albedo;out vec3 v_view;out vec3 v_leaf;out float v_occlusion;out float v_leafy;out float v_detail;out vec4 v_ground;out vec3 v_sun_shadow;void main(){Tree tree=placedTree();int part=int(a_info.x);bool fits=part==TRUNK_PART?tree.species!=BUSH:(part==CONIFER_PART)==(tree.species==CONIFER);if(tree.height<=0.||!fits){gl_Position=LEFT_OUT;return;}vec4 randoms=slotRandoms(tree.slot,2u);vec3 local=a_position;float width=mix(.85,1.2,randoms.x);float stretch=1.;float lobeShade=1.;if(part==BROADLEAF_PART){vec4 lobe=slotRandoms(tree.slot,3u+uint(a_info.y));lobeShade=mix(.92,1.08,fract(lobe.x*7.+lobe.w));local=a_center+vec3((lobe.yz-.5)*.09,(lobe.w-.5)*.05)+(a_position-a_center)*mix(.8,1.15,lobe.x);if(tree.species==BUSH){stretch=1.45;local.z=(local.z-.3)*stretch;width*=1.4;}}vec3 shape=vec3(1.);if(tree.species==COLUMNAR&&part==BROADLEAF_PART){shape=vec3(.42,.42,1.7);local=vec3(local.xy*shape.xy,.6+(local.z-.6)*shape.z);}else if(tree.species==UMBRELLA){shape=part==TRUNK_PART?vec3(1.,1.,1.8):vec3(1.45,1.45,.42);local=part==TRUNK_PART?local*shape:vec3(local.xy*shape.xy,.86+(local.z-.62)*shape.z);}float angle=randoms.y*TAU;mat2 turn=mat2(cos(angle),sin(angle),-sin(angle),cos(angle));vec3 normal=normalize(vec3(turn*(a_normal.xy/(width*shape.xy)),a_normal.z/(shape.z*stretch)));float gust=.012*sin(u_wind_clock*1.4+randoms.z*TAU)+.007*sin(u_wind_clock*3.1+randoms.w*TAU);vec2 across=(turn*local.xy)*width*tree.height+u_wind*gust*local.z*local.z*tree.height;vec2 position=tree.position+across/u_tile_scale;float elevation=local.z*tree.height;float footElevation=groundElevationAt(tree.position);gl_Position=projectTileFor3D(position,footElevation+elevation);v_sun_shadow=(u_tile_to_shadow*vec4(position,footElevation+elevation,1.)).xyz;bool wild=STAND_WILD[tree.stand]>.5;vec3 ground=wild?u_foliage_wild:u_foliage_tended;if(u_foliage_from_ground){vec3 seen=texelFetch(u_placement_ground,u_tile_slot+tree.cell,0).rgb;float greenness=smoothstep(-.02,.05,seen.g-max(seen.r,seen.b));ground=mix(mix(seen,vec3(.85,1.,.7)*luminanceOf(seen),.45),seen,greenness);}float brightness=luminanceOf(ground);vec3 foliage=u_foliage_from_ground?ground:mix(ground*1.35+.03,ground*.74,smoothstep(.2,.6,brightness));foliage*=mix(vec3(1.07,1.02,.84),vec3(.9,1.,1.06),randoms.z)*mix(.86,1.1,randoms.w);bool needles=SPECIES_NEEDLES[tree.species]>.5;vec4 toward=needles?u_conifer_toward:u_broadleaf_toward;vec2 own=slotRandoms(tree.slot,64u).xy;float turned=clamp(toward.a*mix(1.,2.*own.x,u_foliage_variety),0.,1.);vec3 hue=mix(vec3(1.),mix(vec3(1.08,.78,.72),vec3(.98,1.12,.8),own.y),u_foliage_variety);foliage=mix(foliage*(needles?u_conifer_tint:u_broadleaf_tint),toward.rgb*hue,turned);vec3 bark=mix(vec3(.42,.35,.28),ground,.25)*mix(.5,1.,brightness);v_normal=normal;v_albedo=part==TRUNK_PART?bark:foliage*lobeShade;v_view=vec3(u_tile_camera+position*u_tile_scale,footElevation+elevation-u_camera_altitude);v_leaf=vec3(across,elevation);v_occlusion=a_info.z;v_leafy=part==TRUNK_PART?0.:1.;float pixels=tree.height/(length(v_view)*u_pixel_angle);v_detail=smoothstep(18.,60.,pixels);vec3 farColor=mix(ground*(needles?u_conifer_tint:u_broadleaf_tint),toward.rgb,toward.a);v_ground=vec4(farColor,1.-smoothstep(3.,14.,pixels));}\n"),fragmentShader:fragmentSourceOf("\nfloat sunLightAt(highp sampler2DShadow shadowMap,float intensity,vec3 coordinate){\nif(any(lessThan(coordinate,vec3(0.)))||any(greaterThan(coordinate,vec3(1.))))return 1.;\nvec2 texel=1./vec2(textureSize(shadowMap,0));\nfloat lit=textureLod(shadowMap,coordinate,0.);\nfor(int tap=0;tap<4;tap++){\nvec2 offset=vec2(tap==0?1.:tap==1?-1.:0.,tap==2?1.:tap==3?-1.:0.);\nlit+=textureLod(shadowMap,vec3(coordinate.xy+offset*texel,coordinate.z),0.);\n}\nreturn 1.-intensity*(1.-lit/5.);\n}\n","uniform vec3 u_sun;uniform vec3 u_sun_color;uniform vec3 u_sky_color;uniform highp sampler2DShadow u_sun_shadow;uniform float u_sun_shadow_intensity;in vec3 v_normal;in vec3 v_albedo;in vec3 v_view;in vec3 v_leaf;in float v_occlusion;in float v_leafy;in float v_detail;in vec4 v_ground;in vec3 v_sun_shadow;out vec4 fragColor;float noise3(vec3 p){vec3 lower=floor(p);vec3 within=p-lower;within=within*within*(3.-2.*within);uvec3 lattice=uvec3(ivec3(lower)+32768);float corners[8];for(int index=0;index<8;index++){uvec3 corner=lattice+uvec3(index&1,(index>>1)&1,index>>2);corners[index]=halvesOf(hashOf(corner.xy+uvec2(corner.z*0x9E3779B9u,0u))).x;}return mix(mix(mix(corners[0],corners[1],within.x),mix(corners[2],corners[3],within.x),within.y),mix(mix(corners[4],corners[5],within.x),mix(corners[6],corners[7],within.x),within.y),within.z);}void main(){vec3 normal=normalize(v_normal);float leaves=0.;if(v_leafy>.5&&v_detail>0.){vec3 p=v_leaf*1.7;vec3 bump=vec3(noise3(p),noise3(p+19.1),noise3(p+43.7))-.5;normal=normalize(normal+bump*.8*v_detail);leaves=(noise3(p*2.9)-.5)*v_detail;}float sunlight=u_sun_shadow_intensity>0.?sunLightAt(u_sun_shadow,u_sun_shadow_intensity,v_sun_shadow):1.;float facing=dot(normal,u_sun);float wrapped=clamp((facing+.6)/1.6,0.,1.);float lit=wrapped*wrapped*smoothstep(-.05,.2,u_sun.z)*sunlight;vec3 view=normalize(v_view);float through=v_leafy*pow(clamp(dot(view,u_sun),0.,1.),4.)*clamp(.5-facing,0.,1.)*sunlight;vec3 ambient=mix(v_albedo*.8+.04,u_sky_color*.9+.1,.3+.3*normal.z);float edgeOn=pow(1.-clamp(dot(-view,normal),0.,1.),3.)*v_leafy;float sheen=pow(max(dot(reflect(view,normal),u_sun),0.),12.)*lit*v_leafy;vec3 bounce=v_ground.rgb*(.3*clamp(.5-.6*normal.z,0.,1.));vec3 light=u_sun_color*(lit*mix(.6,1.1,v_occlusion)+through*.7)+(ambient*.78+bounce)*v_occlusion;vec3 color=v_albedo*light*(1.+.3*leaves-.12*max(-leaves,0.));color+=u_sun_color*(.06*sheen)+u_sky_color*(.16*edgeOn*v_occlusion);color=mix(color,v_ground.rgb*mix(.82,1.,lit),v_ground.a*.75);fragColor=vec4(clamp(color,0.,1.),1.);}\n"),uniforms:{...tileUniforms(),...uniformsHolding({u_placement:null,u_placement_ground:null,u_wind:[0,0],u_wind_clock:0,u_pixel_angle:0,u_foliage_wild:[0,0,0],u_foliage_tended:[0,0,0],u_foliage_from_ground:!1,u_broadleaf_tint:[0,0,0],u_broadleaf_toward:[0,0,0,0],u_conifer_tint:[0,0,0],u_conifer_toward:[0,0,0,0],u_foliage_variety:0,u_sun:[0,0,0],u_sun_color:[0,0,0],u_sky_color:[0,0,0],u_sun_shadow:null,u_sun_shadow_intensity:0,u_tile_to_shadow:/* @__PURE__ */new Float32Array(16)})},depthTest:!0,depthWrite:!0,depthFunc:LessEqualDepth}),TreesRenderer=class{resources;passes=/* @__PURE__ */new Map;placedView;movedAt;settlingPlacements=0;drewAt;placedSlots=/* @__PURE__ */new Map;draw(e,t,o,r){const{map:a,metersPerMercator:i,uniforms:s}=r,n=fadeInFrom(a.getZoom(),s.trees.minZoom,.75);if(n<=0||s.trees.densityFactor<=0)return!1;const l=2*Math.tan(o.fov/2)/a.getCanvas().clientHeight,c=-Math.log2(192*l);let d=this.placedView;const u=d?.viewKey!==r.viewKey||d.growth!==n||d.trees!==s.trees&&!sameJSON(s.trees,d.trees);if(d&&!u&&(d.trees=s.trees),!d||u){const e=this.placedTilesOf(o,r,l,c);d={viewKey:r.viewKey,growth:n,trees:s.trees,tiles:e},this.placedView=d}const f=d.tiles;if(!f.length)return!1;const h=this.setUp(),m=this.passesOf(o,h),p=this.easeOf(u);return void 0!==this.movedAt&&a.triggerRepaint(),p&&this.place(e,t,h,m.placement,f,r,{lod:c+Math.log2(i),pixelAngle:l,growth:MathUtils.smoothstep(n,0,1),keepStands:u,ease:p}),s.trees.shadowsIntensity>0&&(this.drawShadows(e,h,m.shadows,f,r),s.trees.tracksIntensity>0&&r.before.copy(e,t)),this.drawTrees(e,h,m.trees,f,r,l),s.trees.tracksIntensity>0&&this.drawTracks(e,h,r),!0}placedTilesOf(e,t,o,r){const{map:a,metersPerMercator:i,camera:s,groundMeters:n}=t,l=(({matrix:e,camera:t,lod:o,farthest:r,detailedWithin:a,tallest:i,ground:s})=>{const[n,l,c]=t;frustum.setFromProjectionMatrix(viewMatrix.fromArray(e));const d=s.elevation-s.relief,u=s.elevation+s.relief+i,f=Math.max(c-s.elevation,0),h=[],m=Math.floor(n),p=[-1,0,1].map(e=>({x:0,y:0,z:0,wrap:m+e}));for(let g=p.pop();g;g=p.pop()){const{x:e,y:t,z:i,wrap:s}=g,c=1/2**i,m=[s+e*c,t*c,s+(e+1)*c,(t+1)*c];if(box.min.set(m[0],m[1],d),box.max.set(m[2],m[3],u),!frustum.intersectsBox(box))continue;const v=Math.max(m[0]-n,0,n-m[2]),_=Math.max(m[1]-l,0,l-m[3]),w=Math.hypot(v,_,f);if(!(w>r))if(i<Math.min(17,Math.floor(o-Math.log2(w))))for(let o=0;o<4;o++)p.push({x:2*e+(1&o),y:2*t+(o>>1),z:i+1,wrap:s});else i>=11&&h.push({tile:{canonical:{x:e,y:t,z:i},wrap:s,detailed:w<a},distance:w})}return h.sort((e,t)=>e.distance-t.distance),h.slice(0,256).map(({tile:e})=>e)})({matrix:e.defaultProjectionData.fallbackMatrix,camera:s,lod:r,farthest:40/i/(.8*o),detailedWithin:12/i/(28*o),tallest:40/i,ground:groundOf(a,n)}),c=l.length?terrainTilesOf(a):[],d=s[2]*i;return l.map((o,r)=>{const{scale:i,camera:s}=tilePlacementOf(o,t);return{...o,slot:[r%PLACEMENT_COLUMNS*32,32*Math.floor(r/PLACEMENT_COLUMNS)],projection:projectionOf(e,o),scale:i,camera:s,cameraAltitude:d,terrain:c.length?tileTerrainOf(a,o,c):void 0}})}easeOf(e){const t=performance.now(),o=void 0!==this.drewAt&&t-this.drewAt<50;return this.drewAt=t,e?(this.movedAt=t,this.settlingPlacements=6,MOVING_EASE):void 0===this.movedAt||t-this.movedAt<100?void 0:o&&this.settlingPlacements>0?(this.settlingPlacements--,SETTLING_EASE):(this.movedAt=void 0,FINAL_EASE)}release(){for(const{placement:t,shadows:o,trees:r}of this.passes.values())for(const{material:e}of[t,o,r])e.dispose();this.passes.clear(),this.placedView=void 0,this.movedAt=void 0,this.drewAt=void 0,this.placedSlots.clear();const e=this.resources;if(e){e.placement.dispose(),e.previousPlacement.dispose();for(const t of[e.slotPoints,e.shadowQuads,e.detailed,e.distant])t.dispose();disposePass(e.tracks),this.resources=void 0}}setUp(){return this.resources??={placement:fieldTarget([PLACEMENT_SIZE,PLACEMENT_SIZE],2),previousPlacement:fieldTarget([PLACEMENT_SIZE,PLACEMENT_SIZE],2),slotPoints:vertexIdGeometry(new BufferGeometry,1024),shadowQuads:Object.assign(vertexIdGeometry(new InstancedBufferGeometry,6),{instanceCount:1024}),detailed:instancedTreesOf(meshOf(e=>{(e=>{const t=[0,0,.225],o=(o,r,a)=>Array.from({length:6},(i,s)=>{const n=s/6*Math.PI*2,[l,c]=[Math.cos(n),Math.sin(n)];return add(e,[l*r,c*r,o],[l,c,.15],t,TREE_PARTS.trunk,0,a)}),r=o(0,.04,.85),a=o(.45,.026,.55);for(let i=0;i<6;i++){const t=(i+1)%6;e.indices.push(r[i],r[t],a[t],r[i],a[t],a[i])}})(e),addCrown(e,BROADLEAF_LOBES,1),CONIFER_TIERS.forEach((t,o)=>addTier(e,t,12,.3,o))})),distant:instancedTreesOf(meshOf(e=>{addCrown(e,[{center:[0,0,.6],radius:.33,height:.32}],0),addTier(e,{base:.12,top:1,radius:.24},6,0,0)})),tracks:fullscreenPass({name:"trees tracks",fragmentShader:fragmentSourceOf(standTraitsGlsl(),"uniform sampler2D u_before;uniform sampler2D u_mask;uniform float u_intensity;out vec4 fragColor;void main(){ivec2 texel=ivec2(gl_FragCoord.xy);vec3 mask=texelFetch(u_mask,texel,0).rgb;vec3 before=texelFetch(u_before,texel,0).rgb;float key=(float(TRACK_KEY)*16.+8.)/255.;bool keyed=mask.g>.98&&mask.b<.02&&any(greaterThan(abs(mask-before),vec3(.003)));float track=keyed?smoothstep(key-.18,key-.02,mask.r):0.;if(track<=0.)discard;fragColor=vec4(before,u_intensity*track);}\n"),uniforms:uniformsHolding({u_before:null,u_mask:null,u_intensity:0}),blending:CustomBlending,blendEquation:AddEquation,blendSrc:SrcAlphaFactor,blendDst:OneMinusSrcAlphaFactor})},this.resources}passesOf(e,t){const{variantName:o}=e.shaderData;let r=this.passes.get(o);return r||(r={placement:new TilePass(placementMaterialOf(e),e=>new Points(t.slotPoints,e)),shadows:new TilePass(shadowsMaterialOf(e),e=>new Mesh(t.shadowQuads,e)),trees:new TilePass(treesMaterialOf(e),e=>new Mesh(t.distant,e))},this.passes.set(o,r)),r}place(e,t,o,r,a,{map:i,beforeTexture:s,maskTexture:n,uniforms:l},c){const d=r.material.uniforms;d.u_before.value=s,d.u_mask.value=n,d.u_viewport.value=[t.drawingBufferWidth,t.drawingBufferHeight],d.u_lod.value=c.lod,d.u_pixel_angle.value=c.pixelAngle,d.u_density_factor.value=l.trees.densityFactor,d.u_size_factor.value=l.trees.sizeFactor,d.u_growth.value=c.growth,d.u_keep_stands.value=c.keepStands?1:0,d.u_ease.value=c.ease;const u=i.getCenter().lat;d.u_wild_conifers.value=(e=>.03+.09*MathUtils.smoothstep(Math.abs(e),15,30)+.63*MathUtils.smoothstep(Math.abs(e),47,65))(u),d.u_warm_climate.value=(e=>1-MathUtils.smoothstep(Math.abs(e),40,46))(u),d.u_treeline.value=(e=>3800-3200*MathUtils.smoothstep(Math.abs(e),15,68))(u),d.u_share_factors.value=l.trees.shareFactors,d.u_ground_follows.value=l.trees.foliageFromGround,[o.placement,o.previousPlacement]=[o.previousPlacement,o.placement],d.u_previous.value=o.previousPlacement.textures[0],d.u_previous_ground.value=o.previousPlacement.textures[1],showTiles(r,a,e=>{const{own:t,parent:o,children:r}=((e,{canonical:{x:t,y:o,z:r},wrap:a})=>{const i=(t,o,r)=>e.get(tileKeyOf(a,t,o,r))??NO_SLOT;return{own:i(r,t,o),parent:i(r-1,t>>1,o>>1),children:[0,1,2,3].flatMap(e=>i(r+1,2*t+(1&e),2*o+(e>>1)))}})(this.placedSlots,e);d.u_previous_slot.value=t,d.u_previous_parent_slot.value=o,d.u_previous_child_slots.value.set(r)}),drawInto(e,o.placement,r.scene),this.placedSlots=new Map(a.map(({canonical:{x:e,y:t,z:o},wrap:r,slot:a})=>[tileKeyOf(r,o,e,t),a]))}drawShadows(e,t,o,r,{beforeTexture:a,uniforms:i}){const s=o.material.uniforms;s.u_placement.value=t.placement.textures[0],s.u_before.value=a,s.u_sun.value=i.sun,s.u_shadows_intensity.value=i.trees.shadowsIntensity,o.material.depthTest=r.some(({terrain:e})=>e),showTiles(o,r),drawPass(e,o.scene)}drawTracks(e,{tracks:t},{beforeTexture:o,maskTexture:r,uniforms:a}){const i=t.material.uniforms;i.u_before.value=o,i.u_mask.value=r,i.u_intensity.value=a.trees.tracksIntensity,drawPass(e,t)}drawTrees(e,t,o,r,{map:a,windClock:i,uniforms:s},n){const l=o.material.uniforms,c=((e,t)=>{if(!e)return;const[o,r,a]=towardsSunOf(e.sun.direction,e.sun.altitude);return o*t[0]+r*t[1]+a*t[2]>=SAME_SUN?e:void 0})((e=>shadowMaps.get(e))(a),s.sun);l.u_sun_shadow_intensity.value=c?.intensity??0,l.u_sun_shadow.value=c?.texture??(noSunShadow||((noSunShadow=new DepthTexture(1,1)).compareFunction=LessEqualCompare,noSunShadow.needsUpdate=!0),noSunShadow),l.u_placement.value=t.placement.textures[0],l.u_placement_ground.value=t.placement.textures[1],l.u_wind.value=s.wind,l.u_wind_clock.value=i,l.u_pixel_angle.value=n,l.u_foliage_wild.value=s.trees.foliage.wild,l.u_foliage_tended.value=s.trees.foliage.tended,l.u_foliage_from_ground.value=s.trees.foliageFromGround,l.u_broadleaf_tint.value=s.trees.broadleaf.tint,l.u_broadleaf_toward.value=s.trees.broadleaf.toward,l.u_conifer_tint.value=s.trees.conifer.tint,l.u_conifer_toward.value=s.trees.conifer.toward,l.u_foliage_variety.value=s.trees.variety,l.u_sun.value=s.sun,l.u_sun_color.value=s.trees.sunColor,l.u_sky_color.value=s.skyColor,showTiles(o,r,e=>{c&&((e,t,o=/* @__PURE__ */new Float32Array(16))=>{const{corner:[r,a],size:i}=tileBoundsOf(t),s=i/8192;intoMercator.makeScale(s,s,1).setPosition(r,a,0),o.set(ontoShadowMap.multiplyMatrices(e,intoMercator).elements)})(c.fromMercator,e,l.u_tile_to_shadow.value)}),r.forEach(({detailed:e},r)=>{o.objects[r].geometry=e?t.detailed:t.distant}),drawPass(e,o.scene)}},showTiles=(e,t,o)=>e.show(t.length,(r,a)=>{setTile(r,e.material.uniforms,t[a]),o?.(t[a])}),setTile=(e,t,{canonical:o,slot:r,projection:a,scale:i,camera:s,cameraAltitude:n,terrain:l})=>{setTileGround(e,t,a,l),t.u_tile.value=[o.x,o.y,o.z],t.u_tile_slot.value=r,t.u_tile_scale.value=i,t.u_tile_camera.value=s,t.u_camera_altitude.value=n},MOVING_SURFACES=/* @__PURE__ */new Set(["water","grass"]),gridOf=()=>{const e=[],t=512;for(let o=0;o<16;o++)for(let r=0;r<16;r++){const[a,i,s,n]=[r*t,o*t,(r+1)*t,(o+1)*t];e.push(a,i,s,i,a,n,a,n,s,i,s,n)}return vertexIdGeometry((new BufferGeometry).setAttribute("a_pos",new Int16BufferAttribute(e,2)),e.length/2)},cameraInMercator=(e,t,o)=>{const r=e.getCenter(),{x:a,y:i}=MercatorCoordinate.fromLngLat(r),s=512*2**e.getZoom(),n=.5/Math.tan(t/2)*e.getCanvas().clientHeight/s,l=MathUtils.degToRad(e.getPitch()),c=MathUtils.degToRad(e.getBearing()),d=n*Math.sin(l),u=MercatorCoordinate.fromLngLat(r,o).z;return[a-Math.sin(c)*d,i+Math.cos(c)*d,u+n*Math.cos(l)]},SurfacesRenderer=class{uniformsOf;runs=[];imagerySourceId;resources;materials=/* @__PURE__ */new Map;trees=new TreesRenderer;landField=new LandFieldRenderer;roadField=new RoadFieldRenderer;activeRuns=/* @__PURE__ */new Set;layerIds=/* @__PURE__ */new Set;textureMetersPerMercator;windClockSeconds=0;lastFrameTime;dataVersion=0;imageryVersion=0;onData=e=>{"source"===e.dataType&&(e.sourceId===this.imagerySourceId&&this.imageryVersion++,this.masksDrawFrom(e.sourceId)&&this.dataVersion++)};onTerrain=()=>{this.dataVersion++};frameState;onRender=()=>{this.frameState=void 0};groundTiles;movingInView;reusedLandField;reusedRoadField;constructor(e){this.uniformsOf=e}masksChanged(){this.dataVersion++}beforeLayer(e,t){return{id:e,type:"custom",renderingMode:"3d",onAdd:(t,o)=>this.setUp(t,o,e),onRemove:t=>this.tearDown(t,e),render:e=>this.snapshot(e,t)}}compositeLayer(e,t){return{id:e,type:"custom",renderingMode:"3d",onAdd:(t,o)=>this.setUp(t,o,e),onRemove:t=>this.tearDown(t,e),render:(e,o)=>this.composite(e,t,o)}}setUp(e,t,o){if(!(t instanceof WebGL2RenderingContext))throw new Error("GLSurfaces needs WebGL2.");this.layerIds.add(o),this.resources||(e.on("data",this.onData),e.on("terrain",this.onTerrain),e.on("render",this.onRender),this.resources={map:e,renderer:rendererOf(e,t),before:new DrawingBufferCopy,mask:new DrawingBufferCopy,composite:fullscreenPass({name:"surfaces composite",fragmentShader:fragmentSourceOf(paletteRolesGlsl(),roles_default,masks_default,"uniform sampler2D u_before;uniform sampler2D u_mask;uniform sampler2D u_shaded;uniform float u_intensity[SURFACE_ID_COUNT];uniform bool u_over_imagery;uniform float u_pixels_per_shade;out vec4 fragColor;void main(){ivec2 pixel=ivec2(gl_FragCoord.xy);vec3 before=texelFetch(u_before,pixel,0).rgb;fragColor=vec4(before,1.);int id;float intensity=keyOver(before,texelFetch(u_mask,pixel,0).rgb,id);if(id==0)return;intensity*=u_intensity[id];if(u_over_imagery&&id==WATER)intensity*=smoothstep(-.02,.06,max(before.g,before.b)-before.r);if(intensity<=0.)return;int span=int(u_pixels_per_shade);vec2 inShaded=(vec2(pixel)+.5)/float(span)-.5;ivec2 corner=ivec2(floor(inShaded));vec2 toNext=inShaded-vec2(corner);ivec2 last=textureSize(u_shaded,0)-1;int role=GROUND_ROLES[id];if(span==1){vec4 shade=texelFetch(u_shaded,pixel,0);vec3 surface=int(round(shade.a*255.))==id?shade.rgb:shaded(before,role);fragColor=vec4(clamp(mix(before,surface,intensity),0.,1.),1.);return;}vec3 ground=shaded(before,role);vec3 shades=vec3(0.);vec3 grounds=vec3(0.);float total=0.;for(int index=0;index<4;index++){ivec2 offset=ivec2(index&1,index>>1);ivec2 candidate=clamp(corner+offset,ivec2(0),last);vec4 shade=texelFetch(u_shaded,candidate,0);if(int(round(shade.a*255.))!=id)continue;vec2 nearness=mix(1.-toNext,toNext,vec2(offset));float weight=nearness.x*nearness.y+1e-3;shades+=weight*shade.rgb;grounds+=weight*texelFetch(u_before,candidate*span,0).rgb;total+=weight;}vec3 surface=ground+(total>0.?shades/total-shaded(grounds/total,role):vec3(0.));fragColor=vec4(clamp(mix(before,surface,intensity),0.,1.),1.);}\n"),uniforms:uniformsHolding({u_before:null,u_mask:null,u_shaded:null,u_roles:null,u_intensity:null,u_over_imagery:0,u_pixels_per_shade:1})}),grid:gridOf(),roles:rolesTexture()})}tearDown(e,t){this.layerIds.delete(t);for(const r of this.layerIds)e.getLayer(r)||this.layerIds.delete(r);const o=this.resources;if(!this.layerIds.size&&o){for(const{material:e}of this.materials.values())e.dispose();this.materials.clear(),disposePass(o.composite),o.shaded?.dispose(),o.before.dispose(),o.mask.dispose(),o.grid.dispose(),o.roles.texture.dispose(),o.terrainGrid?.dispose(),this.trees.release(),this.landField.release(),this.roadField.release(),e.off("data",this.onData),e.off("terrain",this.onTerrain),e.off("render",this.onRender),this.onRender(),this.reusedLandField=void 0,this.reusedRoadField=void 0,this.groundTiles=void 0,this.movingInView=void 0,this.resources=void 0,this.activeRuns.clear()}}isRunShowing(e){const t=this.resources?.map,o=this.runs[e];if(!t||!o)return!1;const r=t.getZoom();return o.maskLayerIds.some(e=>!1===t.getLayer(e)?.isHidden(r))}masksDrawFrom(e){const t=this.resources?.map;return!!t&&(t.getTerrain()?.source===e||this.runs.some(({maskLayerIds:o})=>o.some(o=>t.getLayer(o)?.source===e)))}snapshot(e,t){const o=this.resources;o&&this.isRunShowing(t)?(this.activeRuns.add(t),o.renderer.resetState(),o.before.copy(o.renderer,e)):this.activeRuns.delete(t)}composite(e,t,o){const r=this.resources,a=this.runs[t];if(!r||!a||!this.activeRuns.has(t))return;const{renderer:i,before:s,mask:n}=r,l=s.texture;if(!l)return;resetRendererFor(i,e);const c=n.copy(i,e);this.frameState??=this.frameStateOf(e,r.map,o);const{uniforms:d,frame:u}=this.frameState,f=this.advanceWindClock(d.windSpeedFactor),h=`${t}|${this.frameState.viewKey}`;let m;if("materials"===a.pass){const t=this.landFieldOf(e,r,c,o,a,{uniforms:d,frame:u,viewKey:h}),i=this.roadFieldOf(e,r,c,a,d,h);this.drawMaterials(e,r,o,a,{beforeTexture:l,maskTexture:c,uniforms:d,frame:u,frameViewKey:this.frameState.viewKey,windClock:f,landField:t,roadField:i}),m=a.kinds.some(e=>MOVING_SURFACES.has(e)&&d.intensities[e]>0)}else composeOver(r,l,c,{intensities:NO_SURFACES}),m=this.trees.draw(r.renderer,e,o,{...u,map:r.map,before:r.before,beforeTexture:l,maskTexture:c,windClock:f,uniforms:d,viewKey:`${h}|${this.imageryVersion}`})&&r.map.getZoom()>=16;m&&d.windSpeedFactor>0&&this.showsMoving(r.map,t,this.frameState.viewKey)&&r.map.triggerRepaint()}showsMoving(e,t,o){let r=this.movingInView;r?.viewKey!==o&&(r={viewKey:o,byRun:/* @__PURE__ */new Map},this.movingInView=r);const{byRun:a}=r;let i=a.get(t);return void 0===i&&(i=((e,t)=>t.some(t=>{const o=e.getLayer(t)?.source;return!!o&&renderedTilesOf(e,o).some(e=>e.buckets?.[t])}))(e,this.runs[t]?.movingMaskLayerIds??[]),a.set(t,i)),i}materialPass(e){const{variantName:t}=e.shaderData;let o=this.materials.get(t);if(!o){const r=rawMaterial({name:"surfaces materials",vertexShader:vertexSourceOf(e,"in vec2 a_pos;out vec2 v_pos;out float v_elevation;void main(){v_pos=a_pos;v_elevation=groundElevationAt(a_pos);gl_Position=projectTileOnGround(a_pos,v_elevation);}\n"),fragmentShader:fragmentSourceOf(paletteRolesGlsl(),roles_default,masks_default,landField_default,roadField_default,"uniform sampler2D u_before;uniform sampler2D u_mask;uniform float u_intensity[SURFACE_ID_COUNT];uniform vec2 u_tile_origin;uniform vec2 u_tile_origin_wind;uniform float u_tile_scale;uniform vec2 u_tile_camera;uniform float u_camera_altitude;uniform float u_wind_clock;uniform vec2 u_wind;uniform vec3 u_sun;uniform vec3 u_glint_color;uniform vec3 u_sky_color;uniform vec3 u_horizon_color;uniform float u_reflection;uniform float u_glint;uniform mat4 u_ground_matrix;uniform float u_pixels_per_shade;uniform vec4 u_water_pattern;uniform vec2 u_forest_pattern;uniform vec3 u_grass_pattern;uniform vec3 u_farmland_pattern;uniform vec3 u_sand_pattern;uniform float u_rock_pattern;uniform float u_roads_pattern;uniform float u_ice_pattern;uniform float u_scrub_pattern;uniform float u_mud_pattern;uniform float u_gravel_pattern;uniform float u_paving_pattern;uniform float u_urban_pattern;uniform float u_device_pixel_ratio;uniform sampler2D u_land_field;uniform sampler2D u_openness;uniform float u_land_field_fade;uniform sampler2D u_road_field;uniform float u_road_field_fade;in vec2 v_pos;in float v_elevation;out vec4 fragColor;float footprint;vec2 fragCoord;float edgeFootprint;float cssFootprint;ivec2 wrapCell(ivec2 cell,ivec2 period){ivec2 wrapped=cell-period*ivec2(floor(vec2(cell)/vec2(period)));return wrapped+period*(ivec2(lessThan(wrapped,ivec2(0)))-ivec2(greaterThanEqual(wrapped,period)));}float random(ivec2 cell,ivec2 period){return float(hashOf(uvec2(wrapCell(cell,period))))*(1./4294967295.);}vec2 random2(ivec2 cell,ivec2 period){return halvesOf(hashOf(uvec2(wrapCell(cell,period))));}vec2 gradientAt(ivec2 wrapped){uint hash=hashOf(uvec2(wrapped));return normalize(vec2(float(hash&0xffffu),float(hash>>16u))-32767.5);}vec3 gradientNoise(vec2 p,ivec2 period){vec2 i=floor(p);vec2 f=p-i;ivec2 c=wrapCell(ivec2(i),period);ivec2 next=c+1;next-=period*ivec2(equal(next,period));vec2 u=f*f*f*(f*(f*6.-15.)+10.);vec2 du=30.*f*f*(f*(f-2.)+1.);vec2 ga=gradientAt(c);vec2 gb=gradientAt(ivec2(next.x,c.y));vec2 gc=gradientAt(ivec2(c.x,next.y));vec2 gd=gradientAt(next);float va=dot(ga,f);float vb=dot(gb,f-vec2(1.,0.));float vc=dot(gc,f-vec2(0.,1.));float vd=dot(gd,f-vec2(1.,1.));float k=va-vb-vc+vd;float value=va+u.x*(vb-va)+u.y*(vc-va)+u.x*u.y*k;vec2 derivative=ga+u.x*(gb-ga)+u.y*(gc-ga)+u.x*u.y*(ga-gb-gc+gd)+du*(u.yx*k+vec2(vb,vc)-va);return 1.4*vec3(value,derivative);}vec3 noiseWithDerivative(vec2 p,vec2 size){return gradientNoise(p/size,ivec2(PERIOD/size));}float noise(vec2 p,float size){return noiseWithDerivative(p,vec2(size)).x;}float showsAt(float size,float metersPerPixel){return smoothstep(1.5,4.,size/metersPerPixel);}float shows(float size){return showsAt(size,cssFootprint);}float resolves(float wavelength){return 1.-smoothstep(.125,.4,cssFootprint/wavelength);}float rollsInSeen(float wavelength){return resolves(wavelength*.2);}float detail(vec2 p,float size){float visible=shows(size);return visible>0.?visible*noise(p,size):0.;}float fbm(vec2 p,float cell,int octaves){float sum=0.;float amplitude=1.;float total=0.;for(int octave=0;octave<octaves;octave++){total+=amplitude;sum+=amplitude*detail(p,cell);cell*=.5;amplitude*=.6;}return sum/total;}vec2 pixelAt(vec2 offset){vec4 clip=u_ground_matrix*vec4(v_pos+offset/u_tile_scale,v_elevation,1.);return clip.w>0.?(clip.xy/clip.w*.5+.5)*u_viewport:vec2(-1e9);}bool isWaterAt(vec2 offset,bool offView){vec2 pixel=pixelAt(offset);if(any(lessThan(pixel,vec2(-1.)))||any(greaterThan(pixel,u_viewport)))return offView;return isKeyedAs(u_mask,ivec2(clamp(pixel,vec2(0.),u_viewport-1.)),WATER);}bool isWithin(float radius,bool water){for(int index=0;index<SHORE_DIRECTIONS;index++){if(isWaterAt(shoreDirection(index)*radius,!water)==water)return true;}return false;}float nearestWithin(float inside,float outside,bool water,int halvings){for(int halving=0;halving<halvings;halving++){float middle=.5*(inside+outside);if(isWithin(middle,water))outside=middle;else inside=middle;}return .5*(inside+outside);}float waterlineOf(float reach){if(!isWithin(reach,true)&&!isWithin(reach*.5,true))return reach;return nearestWithin(0.,reach,true,5);}float shoreDistanceOf(){bool land=false;for(int index=0;index<SHORE_DIRECTIONS;index++){vec2 direction=shoreDirection(index);land=land||!isWaterAt(direction*SHORE_REACH,true)||!isWaterAt(direction*SHORE_REACH*.4,true);}if(!land)return SHORE_REACH;const float STEPS[6]=float[](2.,4.,8.,13.,20.,30.);float inside=0.;float outside=SHORE_REACH;for(int step=0;step<6;step++){if(isWithin(STEPS[step],false)){outside=STEPS[step];break;}inside=STEPS[step];}return nearestWithin(inside,outside,false,3);}vec3 landFieldAt(){if(u_land_field_fade<=0.)return vec3(1e6,0.,0.);vec2 here=metersAt(fragCoord);ivec2 corner=ivec2(floor(fragCoord/float(FIELD_BLOCK)-.5));ivec2 last=textureSize(u_land_field,0)-1;float nearest=1e12;vec2 toLand=vec2(0.);for(int index=0;index<4;index++){ivec2 texel=clamp(corner+ivec2(index&1,index>>1),ivec2(0),last);ivec2 seed=decodeSeed(texelFetch(u_land_field,texel,0));if(seed.x==NO_SEED)continue;vec2 away=metersAt(vec2(seed)+.5)-here;float distance=dot(away,away);if(distance<nearest){nearest=distance;toLand=away;}}float distance=sqrt(nearest);return vec3(distance,toLand/max(distance,1e-3));}const float NEAR_WAVELENGTH=11.;const float FAR_WAVELENGTH=24.;const float SHOALING=80.;float rollInPhase(float distance,float wobble){return distance/FAR_WAVELENGTH+(1./NEAR_WAVELENGTH-1./FAR_WAVELENGTH)*SHOALING*(1.-exp(-distance/SHOALING))+.11*u_wind_clock+wobble;}float rollInWavelength(float distance){return 1./(1./FAR_WAVELENGTH+(1./NEAR_WAVELENGTH-1./FAR_WAVELENGTH)*exp(-distance/SHOALING));}const float OPEN_WAVELENGTH=32.;float waveFace(float phase){return cos(phase)+.4*cos(2.*phase+.6);}const float SHORE_DETAIL_FOOTPRINT=3.;vec2 quarterWay(int quarter){return quarter==0?vec2(1.,0.):quarter==1?vec2(0.,1.):quarter==2?vec2(-1.,0.):vec2(0.,-1.);}vec3 travellingNoise(vec2 q,float travelled,vec2 size,vec2 way,float across){vec3 sum=vec3(0.);float total=0.;for(int quarter=0;quarter<4;quarter++){vec2 along=quarterWay(quarter);float weight=max(dot(way,along),0.);if(weight<=0.)continue;vec2 side=vec2(-along.y,along.x);vec3 n=noiseWithDerivative(vec2(dot(q,along),dot(q,side))-vec2(travelled,0.),size);sum+=weight*vec3(n.x,n.y*along+across*n.z*side);total+=weight;}return sum/total;}vec3 shore(vec3 color,vec3 base,vec2 p,float distance,float exposed,float wobble){float strength=u_water_pattern.z;float near=1.-smoothstep(0.,SHORE_REACH,distance);color=mix(color,shaded(base,WATER_SHALLOW),near*near*.6*strength);exposed*=strength;if(exposed<=0.||cssFootprint>SHORE_DETAIL_FOOTPRINT)return color;vec3 foamColor=shaded(base,WATER_FOAM)*mix(.55,1.,luminanceOf(u_horizon_color));float streaks=smoothstep(-.25,.35,fbm(p+91.,4.,3));const float WAVELENGTH=NEAR_WAVELENGTH;float phase=rollInPhase(distance,wobble);float front=max(.03,1.5*edgeFootprint/WAVELENGTH);float crest=fract(phase+front);float breaker=smoothstep(0.,front,crest)*(1.-smoothstep(front,front+.4,crest));breaker*=breaker;float sets=smoothstep(-.35,.45,noise(p+vec2(0.,1.92*u_wind_clock),64.));float breakers=breaker*sets*streaks*(1.-smoothstep(6.,40.,distance))*shows(WAVELENGTH*.25);float face=smoothstep(.45,.85,crest)*(1.-smoothstep(.85,1.,crest));color*=1.-.1*face*sets*(1.-smoothstep(4.,30.,distance))*shows(WAVELENGTH*.4)*exposed;vec2 drift=p+vec2(17.,-9.)*.1*u_wind_clock;float patches=fbm(drift+40.,16.,2);float lace=smoothstep(.84,.97,1.-abs(fbm(drift,4.,3)))*smoothstep(-.25,.25,patches)*shows(1.);float milk=.3*smoothstep(.1,.5,patches);float whitewater=(1.-smoothstep(2.,14.,distance))*max(lace,milk)*shows(2.);float runUp=1.2+1.3*(.5+.5*sin(.5*u_wind_clock+5.*noise(p,32.)));float lapping=(1.-smoothstep(.3,runUp,distance))*mix(.6,1.,streaks)*shows(1.5);float foam=max(max(breakers,whitewater*.85),lapping);return mix(color,foamColor,clamp(foam,0.,1.)*exposed);}float trustOf(float landDistance){float edge=insideViewBy(fragCoord)*footprint;return smoothstep(.4,1.,edge/max(landDistance,1.));}vec3 viewDirection(){return normalize(vec3(u_tile_camera+v_pos*u_tile_scale,v_elevation-u_camera_altitude));}vec3 skyAt(float up){return mix(u_horizon_color,u_sky_color,pow(clamp(up,0.,1.),.4));}float facetsAt(vec2 p,float level){uint facet=hashOf(uvec2(ivec2(floor(p/exp2(level))))+uvec2(uint(level+16.)*0x9E3779B9u,0u));vec2 halves=halvesOf(facet);float phase=halves.x;float pace=.5+halves.y;float tilt=.5+.5*sin(TAU*(phase+pace*u_wind_clock));return pow(tilt,6.)*(4096./924.);}float glitterAt(vec2 p){float size=log2(max(cssFootprint*.75,.0625));float level=floor(size);return mix(facetsAt(p,level+1.),facetsAt(p,level+2.),size-level);}float fresnelOf(float facing){return .04+.96*pow(1.-facing,4.);}vec2 sunGlintOf(vec3 toEye,vec3 normal,vec2 variances){vec3 halfway=normalize(toEye+u_sun);float cosTilt=max(dot(halfway,normal),.05);float cos2=cosTilt*cosTilt;vec2 facets=exp((cos2-1.)/(cos2*variances))/(HALF_TURN*variances*cos2*cos2);return facets*fresnelOf(max(dot(toEye,halfway),0.))/(4.*max(dot(toEye,normal),.1));}vec3 water(vec3 base,vec2 windFrame,vec2 p){vec3 land=landFieldAt();bool hasLandField=u_land_field_fade>0.;float farAway=smoothstep(FETCH/16.,FETCH/8.,cssFootprint);vec3 opennessField=hasLandField&&land.x<FETCH?texture(u_openness,fragCoord/float(FIELD_BLOCK)/vec2(textureSize(u_openness,0))).rgb:vec3(1.,.5,.5);float openness=farAway<1.?mix(1.,opennessField.r,u_land_field_fade):1.;float exposed=smoothstep(.2,.45,mix(openness,1.,farAway));float shoreDistance=mix(SHORE_REACH,min(land.x,SHORE_REACH),u_land_field_fade);vec2 searchedUntil=hasLandField?vec2(.6,1.):vec2(2.,3.);if(cssFootprint<searchedUntil.y&&(!hasLandField||land.x<SHORE_REACH+6.*cssFootprint)){shoreDistance=mix(shoreDistanceOf(),shoreDistance,smoothstep(searchedUntil.x,searchedUntil.y,cssFootprint));}float reach=u_water_pattern.w;float rollInShows=1.-smoothstep(.125,.2,cssFootprint/OPEN_WAVELENGTH);float rollIn=land.x<reach&&rollInShows>0.?u_water_pattern.z*u_land_field_fade*exposed*trustOf(land.x)*rollInShows*(1.-smoothstep(.35*reach,reach,land.x)):0.;float sheltered=mix(.55,1.,smoothstep(0.,24.,shoreDistance))*(1.-.5*rollIn);float height=u_water_pattern.x*mix(u_water_pattern.y,1.,exposed)*sheltered;vec2 toLand=opennessField.gb*2.-1.;vec2 toLandInWind=vec2(dot(toLand,u_wind),dot(toLand,vec2(-u_wind.y,u_wind.x)));float nearShore=hasLandField?u_land_field_fade*exposed*(1.-smoothstep(.3*reach,reach,land.x))*step(1e-3,length(toLand)):0.;vec2 way=normalize(mix(vec2(1.,0.),normalize(toLandInWind+vec2(1e-4,0.)),nearShore)+vec2(1e-4,0.));vec2 slope=vec2(0.);float roughness=0.;const float AMPLITUDES[7]=float[](.05,.09,.13,.15,.15,.13,.11);float cell=16.;for(int octave=0;octave<7;octave++){float built=AMPLITUDES[octave]*(cell>=8.?mix(.08,1.,exposed):1.);float resolved=resolves(cell);if(resolved>0.){float travelled=mod(1.25*sqrt(cell)*u_wind_clock,PERIOD);vec3 n=travellingNoise(windFrame+float(octave)*37.,travelled,vec2(cell,cell*2.),way,.5);slope+=built*resolved*(1.+.6*n.x)*n.yz;}roughness+=built*built*(1.-resolved*resolved);cell*=.5;}float swellShows=exposed*(1.-smoothstep(3.,10.,cssFootprint));for(float swell=512.;swell>=128.&&swellShows>0.;swell*=.5){float resolved=resolves(swell)*swellShows;if(resolved<=0.)continue;vec3 n=travellingNoise(windFrame,mod(.4*sqrt(swell)*u_wind_clock,PERIOD),vec2(swell),way,1.);slope+=.02*resolved*n.yz;}float ruffled=exposed>0.?exposed*smoothstep(-.35,.45,fbm(windFrame-vec2(mod(3.*u_wind_clock,PERIOD),0.),128.,2)):0.;slope=(slope.x*u_wind+slope.y*vec2(-u_wind.y,u_wind.x))*height;roughness*=height*height;bool breakers=exposed*u_water_pattern.z>0.&&shoreDistance<SHORE_REACH&&cssFootprint<=SHORE_DETAIL_FOOTPRINT;float wobble=rollIn>0.||breakers?.6*noise(p,128.)+.35*noise(p,32.)+.12*noise(p,8.):0.;if(rollIn>0.){float alongShore=1.-smoothstep(.2*reach,.7*reach,land.x);if(alongShore>0.){float resolved=rollsInSeen(rollInWavelength(land.x));float face=waveFace(TAU*rollInPhase(land.x,wobble));slope-=normalize(toLand+vec2(1e-4,0.))*(.3*rollIn*alongShore*resolved*face);roughness+=.01*rollIn*alongShore*(1.-resolved);}if(alongShore<1.){float resolved=rollsInSeen(OPEN_WAVELENGTH);vec2 faces=vec2(0.);float total=0.;for(int quarter=0;quarter<4;quarter++){vec2 along=quarterWay(quarter);float weight=max(dot(way,along),0.);if(weight<=0.)continue;float phase=dot(windFrame,along)/OPEN_WAVELENGTH-.11*u_wind_clock+wobble;faces+=weight*waveFace(TAU*phase)*(along.x*u_wind+along.y*vec2(-u_wind.y,u_wind.x));total+=weight;}slope-=faces/total*(.3*rollIn*(1.-alongShore)*resolved);roughness+=.01*rollIn*(1.-alongShore)*(1.-resolved);}}vec3 view=viewDirection();vec3 normal=normalize(vec3(-slope*mix(.35,1.,smoothstep(.05,.6,-view.z)),1.));vec3 reflected=reflect(view,normal);vec3 sky=mix(skyAt(reflected.z),base,.5*smoothstep(0.,-.3,reflected.z));float fresnel=fresnelOf(clamp(dot(-view,normal),0.,1.));vec3 color=base*(.84-.25*dot(slope,normalize(u_sun.xy+1e-4))*(1.-u_sun.z));float calm=1.-exposed;float mirrors=(fresnel*(1.+.8*calm)+.1*calm)*(1.+.1*exposed-.2*ruffled);color=mix(color,sky,clamp(mirrors*u_reflection,0.,1.));float toSun=max(dot(reflected,u_sun),0.);float gusts=mix(1.,.65,exposed)+.9*ruffled;float variance=min((.0015+.17*roughness)*gusts,.045);vec2 lobes=sunGlintOf(-view,normal,vec2(variance,.05));float path=pow(toSun,8.)*.08*(1.-u_sun.z);float sparkles=mix(.35,.85,1.-smoothstep(.00125,.0125,variance))*(1.-smoothstep(.75,6.,cssFootprint));float glint=.45*lobes.x;if(sparkles>0.&&glint>.01)glint*=mix(1.,glitterAt(p),sparkles);glint+=.08*lobes.y+path;color+=u_glint_color*(1.-exp(-u_glint*glint));return shoreDistance<SHORE_REACH?shore(color,base,p,shoreDistance,exposed,wobble):color;}float crownAt(vec2 q,ivec2 period,out vec3 normal,out float shape,out float tone,out float conifer){ivec2 home=ivec2(floor(q));float top=0.;normal=vec3(0.,0.,1.);shape=0.;tone=.5;conifer=0.;for(int y=-1;y<=1;y++){for(int x=-1;x<=1;x++){ivec2 neighbour=home+ivec2(x,y);vec2 randoms=random2(neighbour,period);vec2 kind=random2(neighbour+ivec2(17,3),period);vec2 center=vec2(neighbour)+.5+(randoms-.5)*.85;float isConifer=float(kind.y>1.-u_forest_pattern.y);float radius=mix(.45+.45*kind.x,.3+.25*kind.x,isConifer);vec2 offset=(q-center)/radius;float branches=0.;if(isConifer>.5){branches=atan(offset.y,offset.x)*9.+TAU*randoms.y;offset/=1.+.11*sin(branches);}float squared=dot(offset,offset);if(squared>=1.)continue;float reach=sqrt(squared);float up=isConifer>.5?1.-reach:sqrt(1.-squared);float height=up*radius*mix(1.,2.2,isConifer);if(height>top){top=height;vec2 outward=offset/max(reach,1e-3);vec2 across=vec2(-outward.y,outward.x)*cos(branches)*.45;normal=isConifer>.5?normalize(vec3(outward*.9+across,.5)):normalize(vec3(offset,up));shape=up;tone=randoms.x;conifer=isConifer;}}}return top;}vec3 forest(vec3 base,vec2 p){vec3 color=base*(1.+.18*fbm(p,128.,5));float crownCells=max(round(PERIOD/u_forest_pattern.x),1.);float crownSize=PERIOD/crownCells;float crownsShow=shows(crownSize);if(crownsShow<=0.)return color;float outlineShows=shows(4.);vec2 warp=outlineShows>0.?vec2(noise(p,4.),noise(p+37.,4.))*1.1*outlineShows:vec2(0.);vec2 q=(p+warp)/crownSize;ivec2 period=ivec2(int(crownCells));vec3 normal;float shape;float tone;float conifer;float top=crownAt(q,period,normal,shape,tone,conifer);vec3 bumps=noiseWithDerivative(p,vec2(2.));float clumpsShow=shows(1.);vec3 clumps=clumpsShow>0.?bumps+.5*noiseWithDerivative(p,vec2(1.)):vec3(0.);normal=normalize(normal+vec3(clumps.yz*mix(.35,.15,conifer),0.)*clumpsShow);float leaves=detail(p,.25)+.6*clumps.x*clumpsShow;float shade=0.;float shadowsShow=shows(2.);if(shadowsShow>0.&&u_sun.z<.98){vec2 toSun=normalize(u_sun.xy);float rise=u_sun.z/length(u_sun.xy);vec3 ignoredNormal;float ignored;for(int hop=1;hop<=2;hop++){float along=.22*float(hop);float blocker=crownAt(q+toSun*along,period,ignoredNormal,ignored,ignored,ignored);shade=max(shade,smoothstep(0.,.12,blocker-top-along*rise));}shade*=shadowsShow;}float lit=clamp(dot(normal,u_sun),0.,1.)*(1.-.75*shade);vec3 leaf=mix(shaded(color,FOREST_BROADLEAF),shaded(color,FOREST_CONIFER),conifer)*(.84+.3*tone);float rim=mix(.62,1.,smoothstep(0.,.6,shape));vec3 crown=leaf*rim*(.5+.62*lit)*(1.+.1*leaves);vec3 ground=color*(.42+.08*bumps.x)*(1.-.35*shade);return mix(color,top>0.?crown:ground,crownsShow);}vec3 cellsAt(vec2 p,float cell,float jitter,out vec2 toNearest,out ivec2 nearestCell){vec2 q=p/cell;ivec2 home=ivec2(floor(q));ivec2 period=ivec2(int(PERIOD/cell));float nearest=8.;float second=8.;nearestCell=home;toNearest=vec2(0.);for(int y=-1;y<=1;y++){for(int x=-1;x<=1;x++){ivec2 neighbour=home+ivec2(x,y);vec2 offset=vec2(neighbour)+.5+(random2(neighbour,period)-.5)*jitter-q;float squared=dot(offset,offset);if(squared<nearest){second=nearest;nearest=squared;nearestCell=neighbour;toNearest=offset*cell;}else if(squared<second){second=squared;}}}return vec3(sqrt(nearest),sqrt(second),random(nearestCell+ivec2(7,13),period));}vec3 cellsAt(vec2 p,float cell,out vec2 toNearest){ivec2 nearestCell;return cellsAt(p,cell,1.,toNearest,nearestCell);}float stripes(float across,float width){return clamp(sin(TAU*across/(2.*width))*width/(2.*edgeFootprint),-1.,1.);}vec3 grass(vec3 base,vec2 p,vec2 windFrame){float warp=24.*fbm(p+57.,32.,2);float patches=fbm(p+vec2(warp,-warp)+211.,128.,3);vec3 color=mix(shaded(base,GRASS_LUSH),shaded(base,GRASS_DRY),smoothstep(0.,.32,patches)*.75);color*=1.+.05*(.5-abs(fbm(p+5.,8.,3)));vec2 toLawn;vec3 lawn=cellsAt(p,128.,toLawn);float mown=float(lawn.z<u_grass_pattern.x);if(mown>0.){float angle=lawn.z/u_grass_pattern.x*TAU;float across=dot(-toLawn,vec2(-sin(angle),cos(angle)));color*=1.+.09*u_grass_pattern.y*stripes(across,3.)*shows(3.);}color*=1.+.07*fbm(p+3.,.5,2);float bladesShow=shows(.125);if(bladesShow>0.){float blades=noiseWithDerivative(windFrame,vec2(.5,.0625)).x;color*=1.+.07*blades*bladesShow;}float gust=fbm(windFrame-vec2(mod(4.*u_wind_clock,PERIOD),0.),64.,2);color*=1.+.07*smoothstep(.05,.45,gust);vec2 cell=floor(p*2.);vec2 flower=random2(ivec2(cell),ivec2(int(PERIOD*2.)));if(mown==0.&&flower.x<u_grass_pattern.z){vec2 center=(cell+.25+.5*random2(ivec2(cell)+ivec2(3,5),ivec2(int(PERIOD*2.))))/2.;float petals=1.-smoothstep(.05,.05+edgeFootprint,length(p-center));vec3 bloom=flower.y<.6?vec3(.97,.96,.9):shaded(base,GRASS_FLOWERS);color=mix(color,bloom,petals*shows(.1));}return color;}vec3 farmland(vec3 base,vec2 p){float regionSize=1024.;ivec2 period=ivec2(int(PERIOD/regionSize));vec2 toRegion;ivec2 region;vec3 regions=cellsAt(p,regionSize,.8,toRegion,region);float nearest=regions.x;float second=regions.y;ivec2 regionId=wrapCell(region,period);vec2 randoms=random2(regionId+ivec2(3,7),period);float angle=randoms.x*HALF_TURN;vec2 along=vec2(cos(angle),sin(angle));vec2 local=-toRegion;vec2 uv=vec2(dot(local,along),dot(local,vec2(-along.y,along.x)));float parcelScale=u_farmland_pattern.x;float rowDepthScale=2.*u_farmland_pattern.y;float rowLength=(160.+160.*randoms.y)*parcelScale;float row=floor(uv.y/rowLength);uint rowHash=hashOf(uvec2(regionId*977)+uvec2(ivec2(int(row)+4096,11)));float rowRandom=halvesOf(rowHash).x;float parcelWidth=(35.+90.*rowRandom)*parcelScale;float across=uv.x/parcelWidth+rowRandom*7.;float column=floor(across);uint parcelHash=hashOf(uvec2(rowHash,uint(int(column)+65536)));vec2 parcel=halvesOf(parcelHash);vec3 soil=shaded(base,FARMLAND_SOIL);vec3 crop;float rowSpacing;float rowDepth;bool tramlines=true;if(parcel.x<.3){crop=shaded(base,FARMLAND_YOUNG);rowSpacing=.75;rowDepth=.1;}else if(parcel.x<.5){crop=shaded(base,FARMLAND_CEREAL);rowSpacing=.25;rowDepth=.04;}else if(parcel.x<.66){crop=soil;rowSpacing=.5;rowDepth=.12;tramlines=false;}else if(parcel.x<.84){crop=shaded(base,FARMLAND_PASTURE);rowSpacing=0.;rowDepth=0.;tramlines=false;}else if(parcel.x<.9){crop=shaded(base,FARMLAND_RAPESEED);rowSpacing=.5;rowDepth=.03;}else{crop=shaded(base,FARMLAND_STUBBLE);rowSpacing=.25;rowDepth=.06;}vec3 color=mix(base,crop,shows(parcelWidth*.3));color*=1.+.06*fbm(p+31.,64.,3);float toSide=min(fract(across),1.-fract(across))*parcelWidth;float toEnd=min(fract(uv.y/rowLength),1.-fract(uv.y/rowLength))*rowLength;float rowsAcross=toEnd<7.?uv.y:uv.x;if(rowSpacing>0.){color*=1.+rowDepth*rowDepthScale*sin(TAU*rowsAcross/rowSpacing)*shows(rowSpacing);float pass=stripes(rowsAcross+rowRandom*8.,4.+4.*parcel.y);color*=1.+.015*rowDepthScale*pass*shows(8.);}else{color*=1.+.06*(.5-abs(fbm(p,4.,2)));}if(tramlines&&toEnd>=7.){float tram=mod(uv.x+rowRandom*20.,20.)-10.;float wheel=min(abs(tram-.9),abs(tram+.9));float track=1.-smoothstep(.22,.22+edgeFootprint,wheel);color=mix(color,soil,track*.55*shows(.45));}float toEdge=min(toSide,toEnd);float track=(1.-smoothstep(.8,1.8,toEdge))*shows(3.);float hedge=(1.-smoothstep(1.5,4.,(second-nearest)*regionSize))*shows(6.);color=mix(color,base*vec3(.93,.9,.84),track*.7);return mix(color,shaded(base,FARMLAND_HEDGES),hedge*u_farmland_pattern.z);}float sunlitBy(vec2 gradient,float relief){vec3 normal=normalize(vec3(-gradient*relief,1.));return clamp(dot(normal,u_sun)/max(u_sun.z,.25),0.,1.8);}float duneAt(vec2 p){float ridge=1.-abs(fbm(p,256.,3));return ridge*ridge;}vec3 sand(vec3 base,vec2 p,vec2 windFrame){vec3 color=base;float dunes=2.*u_sand_pattern.x;if(dunes>0.){float probe=6.;float height=duneAt(p);vec2 gradient=vec2(duneAt(p+vec2(probe,0.))-height,duneAt(p+vec2(0.,probe))-height)/probe;color*=1.+dunes*(.07*sunlitBy(gradient,30.)-.06);}float ripples=2.*u_sand_pattern.y;float ripple=fract(windFrame.x/.5+6.*fbm(p,8.,2));float slope=ripple<.7?mix(-1.,1.,smoothstep(0.,.3,ripple)):mix(1.,-1.,smoothstep(.7,1.,ripple));color*=1.+.04*ripples*slope*shows(.5);float drifts=noiseWithDerivative(windFrame,vec2(32.,4.)).x;color*=1.+.035*ripples*drifts*shows(4.);float grain=random(ivec2(floor(p*16.)),ivec2(int(PERIOD*16.)));color*=1.+.08*(grain-.5)*shows(.125);color*=1.+.03*fbm(p,1.,2);float width=u_sand_pattern.z;if(width>0.&&cssFootprint<2.){float waterline=waterlineOf(1.5*width+2.);float runUp=width*(1.+.5*noise(p,16.));float wet=(1.-smoothstep(max(runUp-1.5,0.),runUp,waterline))*shows(2.);color=mix(color,shaded(base,SAND_WET),.85*wet);color=mix(color,u_horizon_color,.15*wet*(1.-smoothstep(0.,1.5,waterline)));}return color;}vec3 rock(vec3 base,vec2 p){float ridges=1.-abs(fbm(p,64.,5));return base*(.98+.48*u_rock_pattern*(ridges*ridges-.5)+.08*fbm(p,2.,3));}vec3 mirrored(vec3 color,float wetness){float up=-viewDirection().z;float fresnel=fresnelOf(clamp(up,0.,1.));return mix(color,skyAt(up),clamp((.2+.8*fresnel)*wetness,0.,1.));}vec3 ice(vec3 base,vec2 p){float probe=8.;float height=fbm(p,256.,3);vec2 gradient=vec2(fbm(p+vec2(probe,0.),256.,3)-height,fbm(p+vec2(0.,probe),256.,3)-height)/probe;vec3 color=base*(1.+.06*(sunlitBy(gradient,40.)-1.))*(1.+.02*fbm(p,1.,2));float strength=u_ice_pattern;vec3 blue=shaded(base,ICE_CREVASSES);float scoured=smoothstep(.25,.6,fbm(p+47.,128.,3));color=mix(color,mix(base,blue,.4),.6*scoured*strength);vec2 toField;vec3 field=cellsAt(p,256.,toField);float rifted=strength*smoothstep(.1,.4,fbm(p+131.,256.,2))*smoothstep(0.,.12,field.y-field.x);if(rifted>0.){float angle=field.z*TAU;vec2 local=-toField;float spacing=24.+24.*field.z;float across=dot(local,vec2(cos(angle),sin(angle)))/spacing+.5*noise(p,64.);float fromRift=abs(fract(across)-.5)*spacing;float width=2.5*smoothstep(-.2,.5,noise(p,32.));float rift=1.-smoothstep(width,width+edgeFootprint,fromRift);color=mix(color,blue*.62,rift*rifted*shows(4.));}return color;}vec3 scrub(vec3 base,vec2 p){vec3 color=base*(1.+.06*fbm(p+23.,64.,3))*(1.+.05*(.5-abs(fbm(p+5.,8.,2))));float strength=u_scrub_pattern;if(strength<=0.)return color;vec3 bushColor=shaded(base,SCRUB_BUSHES);float clumped=smoothstep(-.3,.3,fbm(p+301.,32.,2));vec2 toBush;vec3 bush=cellsAt(p,4.,toBush);float present=step(bush.z,.25+.55*clumped);float radius=.7+.9*fract(bush.z*7.);float bushesShow=shows(2.*radius);color=mix(color,mix(color,bushColor,.4*clumped),strength*(1.-bushesShow));if(present<=0.||bushesShow<=0.)return color;vec2 away=-toBush/radius;float squared=dot(away,away);vec2 sunward=u_sun.xy/max(length(u_sun.xy),1e-3);float shadowShift=radius*min(.8,.5/max(u_sun.z,.2));float shadow=1.-smoothstep(radius-edgeFootprint,radius+edgeFootprint,length(-toBush+sunward*shadowShift));color*=1.-.3*shadow*strength*bushesShow;if(squared<1.){vec3 normal=normalize(vec3(away,sqrt(1.-squared)));float lit=clamp(dot(normal,u_sun),0.,1.);vec3 leaf=bushColor*(.6+.55*lit)*(.9+.2*fract(bush.z*13.))*(1.+.08*detail(p,.25));float edge=1.-smoothstep(1.-edgeFootprint/radius,1.,sqrt(squared));color=mix(color,leaf,edge*strength*bushesShow);}return color;}vec3 mud(vec3 base,vec2 p){vec3 color=base*(.94+.08*fbm(p+61.,32.,3))*(1.+.03*fbm(p,1.,2));float strength=u_mud_pattern;vec3 wetColor=shaded(base,MUD_WET);float damp=smoothstep(-.2,.4,fbm(p+17.,128.,2));color=mix(color,wetColor,.45*damp);float meander=fbm(p+7.,128.,3);float creekWidth=.025+.5*edgeFootprint/128.;float creek=(1.-smoothstep(creekWidth,2.*creekWidth,abs(meander)))*shows(2.);float puddle=smoothstep(.32,.42,fbm(p+211.,16.,2))*shows(1.);float water=strength*max(creek,puddle*damp);color=mix(color,wetColor*.85,water);return mirrored(color,water);}vec3 gravel(vec3 base,vec2 p){float strength=u_gravel_pattern;float banks=1.-abs(fbm(p+83.,32.,3));vec3 color=base*(1.+strength*(.16*(banks*banks-.5)+.08*fbm(p+9.,4.,2)));float pebblesShow=shows(.5);if(pebblesShow>0.){vec2 toPebble;vec3 pebbles=cellsAt(p,.5,toPebble);color*=1.+.2*strength*(pebbles.z-.5)*pebblesShow;}float stonesShow=shows(.125)*strength;if(stonesShow<=0.)return color;vec2 toStone;vec3 stone=cellsAt(p,.125,toStone);float gap=1.-smoothstep(0.,.3,stone.y-stone.x);vec2 sunward=u_sun.xy/max(length(u_sun.xy),1e-3);float lit=dot(-toStone/.0625,sunward)*(1.-u_sun.z);float shade=(.82+.36*stone.z)*(1.+.12*lit)*(1.-.3*gap);return color*mix(1.,shade,stonesShow);}vec3 paving(vec3 base,vec2 p){vec3 color=base*(1.+.04*fbm(p+17.,32.,3));vec2 toStretch;vec3 stretch=cellsAt(p,128.,toStretch);vec2 size=stretch.z<.4?vec2(1.):(stretch.z<.75?vec2(.5):vec2(.25,.125));vec2 q=p/size;float row=floor(q.y);q.x+=.5*mod(row,2.);ivec2 stone=ivec2(floor(q));vec2 within=fract(q);vec2 toJoint=min(within,1.-within)*size;float stoneTone=random(stone,ivec2(PERIOD/size));color*=1.+.07*(stoneTone-.5)*shows(size.x);float joints=u_paving_pattern*shows(size.y*.5)*smoothstep(0.,.05,stretch.y-stretch.x);float joint=1.-smoothstep(.008,.008+edgeFootprint,min(toJoint.x,toJoint.y));return mix(color,shaded(color,PAVING_JOINTS),joint*joints);}vec3 urban(vec3 base,vec2 p){float wear=2.*u_urban_pattern;float lots=fbm(p+151.,64.,2);float stains=detail(p,8.);return base*(1.+wear*(.04*lots-.035*smoothstep(.2,.6,stains)));}struct RoadPlace{float fromMiddle;float halfWidth;vec2 across;float sureness;};RoadPlace roadPlaceAt(){RoadPlace place=RoadPlace(0.,0.,vec2(0.,1.),0.);if(u_road_field_fade<=0.)return place;vec2 blocks=(fragCoord-.5*float(FIELD_BLOCK))/float(FIELD_BLOCK);ivec2 corner=ivec2(floor(blocks));vec2 within=blocks-vec2(corner);ivec2 last=textureSize(u_road_field,0)-1;vec2 across=vec2(0.);float total=0.;for(int index=0;index<4;index++){ivec2 step=ivec2(index&1,index>>1);ivec2 block=clamp(corner+step,ivec2(0),last);vec4 texel=texelFetch(u_road_field,block,0);if(texel.a<=0.)continue;RoadAxis axis=decodeRoadAxis(texel);vec2 weights=mix(1.-within,within,vec2(step));float weight=weights.x*weights.y+1e-4;if(dot(axis.across,across)<0.){axis.across=-axis.across;axis.offset=-axis.offset;}place.fromMiddle+=weight*abs(axis.offset+dot(roadBlockCenter(block)-fragCoord,axis.across));place.halfWidth+=weight*axis.halfWidth;place.sureness+=weight*axis.sureness;across+=weight*axis.across;total+=weight;}if(total<=0.)return place;place.fromMiddle/=total;place.halfWidth/=total;place.sureness*=u_road_field_fade/total;place.across=normalize(across);return place;}const float LANE_WIDTH=3.25;vec3 asphalt(vec3 base,vec2 p,mat2 toGround){float wear=2.*u_roads_pattern;float stain=fbm(p+13.,16.,3);RoadPlace road=roadPlaceAt();vec2 acrossGround=toGround*road.across;vec2 along=road.sureness>0.?normalize(vec2(-acrossGround.y,acrossGround.x)):vec2(0.);float aligned=smoothstep(.35,.6,road.sureness)*step(1.,road.halfWidth);float metersPerPixel=length(acrossGround);float halfWidth=road.halfWidth*metersPerPixel;float fromMiddle=min(road.fromMiddle*metersPerPixel,halfWidth);float stains=stain;float wobble=0.;if(aligned>0.){float drift=3.*noise(p,32.);wobble=noise(p,8.);float streak=gradientNoise(vec2(fromMiddle/1.1,drift+.4*wobble),ivec2(PERIOD/1.1)).x;stains=mix(stain,streak,aligned*showsAt(1.1,metersPerPixel*u_device_pixel_ratio));}vec3 color=base*(1.+wear*(.03*smoothstep(.1,.6,-stains)-.045*smoothstep(.05,.6,stains)));float lanes=max(1.,floor(halfWidth/LANE_WIDTH+.35));float lanePixels=road.halfWidth/lanes;float lanesShow=aligned*smoothstep(5.,10.,lanePixels/u_device_pixel_ratio);if(lanesShow>0.&&wear>0.){float pixel=u_pixels_per_shade/lanePixels;float inLane=fract(fromMiddle/halfWidth*lanes);float fromLaneMiddle=abs(inLane-.5);float use=.6+.4*fbm(p+71.,32.,2);float spread=max(.09,.8*pixel);float fromPath=(fromLaneMiddle-.26)/spread;float fromDrip=fromLaneMiddle/spread;float paths=exp(-fromPath*fromPath);float drip=exp(-fromDrip*fromDrip);float sealed=smoothstep(-.1,.3,wobble);float joint=(1.-smoothstep(.5*pixel,1.5*pixel,min(inLane,1.-inLane)))*sealed;float kerb=smoothstep(1.-max(.25/lanes,2.*pixel/lanes),1.,fromMiddle/halfWidth);color*=1.+lanesShow*wear*use*(.04*paths-.06*drip-.04*joint-.05*kerb);}float patchesShow=shows(1.5);vec2 toPatch;vec3 patchCell=patchesShow>0.&&wear>0.?cellsAt(p,32.,toPatch):vec3(1.);if(patchCell.z<.3){float angle=patchCell.z*30.;vec2 lengthwise=road.sureness>0.?along:vec2(cos(angle),sin(angle));vec2 local=vec2(dot(-toPatch,lengthwise),dot(-toPatch,vec2(-lengthwise.y,lengthwise.x)));vec2 halfSize=vec2(1.2+8.*patchCell.z,.8+4.*patchCell.z);vec2 outside=abs(local)-halfSize;float edge=max(outside.x,outside.y);float inside=1.-smoothstep(-edgeFootprint,edgeFootprint,edge);float seam=1.-smoothstep(.04,.04+edgeFootprint,abs(edge));color*=1.-wear*(.06*inside+.06*seam*shows(.15))*patchesShow;}float cracksShow=shows(.1);if(cracksShow>0.&&wear>0.&&stain>.15){vec2 toSlab;vec2 wander=vec2(noise(p,2.),noise(p+19.,2.))*.5;vec3 slabs=cellsAt(p+wander,2.,toSlab);float crack=(1.-smoothstep(0.,(.03+edgeFootprint)/2.,slabs.y-slabs.x))*smoothstep(.15,.35,stain);color*=1.-.12*wear*crack*cracksShow;}return color*(1.+.02*fbm(p,.5,3)+.015*detail(p,.125));}vec3 roads(vec3 base,vec2 p,mat2 toGround){float light=smoothstep(.7,.95,luminanceOf(base));base*=1.-.08*light;return mix(base,asphalt(base,p,toGround),1.+.6*light);}void main(){fragCoord=floor(gl_FragCoord.xy)*u_pixels_per_shade+.5;vec2 offset=v_pos*u_tile_scale;vec2 p=u_tile_origin+offset;vec2 windFrame=u_tile_origin_wind+vec2(dot(offset,u_wind),dot(offset,vec2(-u_wind.y,u_wind.x)));mat2 toGround=mat2(dFdx(p),dFdy(p))/u_pixels_per_shade;footprint=max(length(toGround[0]),length(toGround[1]));edgeFootprint=footprint*u_pixels_per_shade;cssFootprint=footprint*u_device_pixel_ratio;ivec2 pixel=ivec2(fragCoord);vec3 before=texelFetch(u_before,pixel,0).rgb;int id;if(keyOver(before,texelFetch(u_mask,pixel,0).rgb,id)<=0.||u_intensity[id]<=0.)discard;int groundRole=GROUND_ROLES[id];vec3 ground=shaded(before,groundRole);vec3 surface=ground;if(id==WATER)surface=water(ground,windFrame,p);else if(id==FOREST)surface=forest(ground,p);else if(id==GRASS)surface=grass(ground,p,windFrame);else if(id==FARMLAND)surface=farmland(ground,p);else if(id==SAND)surface=sand(ground,p,windFrame);else if(id==ROCK)surface=rock(ground,p);else if(id==ROADS)surface=roads(ground,p,toGround);else if(id==ICE)surface=ice(ground,p);else if(id==SCRUB)surface=scrub(ground,p);else if(id==MUD)surface=mud(ground,p);else if(id==GRAVEL)surface=gravel(ground,p);else if(id==PAVING)surface=paving(ground,p);else if(id==URBAN)surface=urban(ground,p);surface=mix(surface,ground,.6*texelFetch(u_roles,ivec2(groundRole,1),0).a);fragColor=vec4(clamp(surface,0.,1.),float(id)/255.);}\n"),uniforms:{...tileGroundUniforms(),...uniformsHolding({u_ground_matrix:/* @__PURE__ */new Float32Array(16),u_tile_origin:[0,0],u_tile_origin_wind:[0,0],u_tile_scale:0,u_tile_camera:[0,0],u_before:null,u_mask:null,u_intensity:new Float32Array(SURFACE_ID_COUNT),u_camera_altitude:0,u_wind_clock:0,u_wind:[0,0],u_sun:[0,0,0],u_glint_color:[0,0,0],u_sky_color:[0,0,0],u_horizon_color:[0,0,0],u_reflection:0,u_glint:0,u_viewport:[0,0],u_pixels_per_shade:1,u_roles:null,...Object.fromEntries(surfaceKinds.map(e=>[`u_${e}_pattern`,0])),u_land_field:null,u_openness:null,u_device_pixel_ratio:1,u_land_field_fade:0,u_meters_from_clip:/* @__PURE__ */new Float32Array(9),u_road_field:null,u_road_field_fade:0})},depthFunc:LessEqualDepth});o=new TilePass(r,e=>new Mesh(void 0,e)),this.materials.set(t,o)}return o}advanceWindClock(e){const t=performance.now(),o=void 0===this.lastFrameTime?0:Math.min((t-this.lastFrameTime)/1e3,.1);return this.lastFrameTime=t,this.windClockSeconds=(this.windClockSeconds+o*e)%3600,this.windClockSeconds}frameStateOf(e,t,o){const r=this.uniformsOf(),a=[t.getZoom(),o.defaultProjectionData.mainMatrix.join(),e.drawingBufferWidth,e.drawingBufferHeight,this.dataVersion].join("|");return{uniforms:r,frame:this.frameOf(t,o,r),viewKey:a}}frameOf(e,t,{wind:o}){const r=metersPerMercatorAt(e.getCenter().lat);(void 0===this.textureMetersPerMercator||e.getZoom()<9||Math.abs(r/this.textureMetersPerMercator-1)>.05)&&(this.textureMetersPerMercator=r);const a=e.getCenterElevation();return{metersPerMercator:this.textureMetersPerMercator,camera:cameraInMercator(e,t.fov,a),groundMeters:groundElevationAt(e,e.getCenter()),wind:o}}landFieldOf(e,{map:t,renderer:o},r,a,{kinds:i},{uniforms:s,frame:n,viewKey:l}){const c=t.getZoom();if(!i.includes("water")||s.intensities.water<=0||c<=12.5)return;if(this.reusedLandField?.key===l)return this.reusedLandField.field;const d=Math.floor(c),u=2**d,f=MercatorCoordinate.fromLngLat(t.getCenter()),h=e=>MathUtils.clamp(Math.floor(e*u),0,u-1),m={canonical:{x:h(f.x),y:h(f.y),z:d},wrap:0},p=projectionOf(a,m),g=n.groundMeters,v=tilePlacementOf(m,n).scale,_=((e,t,o=0)=>{const[r,a,i]=groundRowsOf(e,o),s=(new Matrix3).set(...r,...a,...i).invert().premultiply((new Matrix3).makeScale(t,t));return new Float32Array(s.elements)})(p.fallbackMatrix,v,g),w=((e,t,o=0)=>{const r=groundRowsOf(e,o);return new Float32Array([0,1,2].flatMap(e=>r.map(o=>o[e]/(e<2?t:1))))})(p.fallbackMatrix,v,g),y={textures:this.landField.build(o,e,r,{metersFromClip:_,clipFromMeters:w}),metersFromClip:_,fade:fadeInFrom(c,12.5,.5)};return this.reusedLandField={key:l,field:y},y}roadFieldOf(e,{map:t,renderer:o},r,{lanes:a},i,s){const n=t.getZoom();if(!a||i.intensities.roads<=0||n<=15)return;if(this.reusedRoadField?.key===s)return this.reusedRoadField.field;const l={texture:this.roadField.build(o,e,r),fade:fadeInFrom(n,15,.5)};return this.reusedRoadField={key:s,field:l},l}drawMaterials(e,t,o,{kinds:r,overImagery:a},{beforeTexture:i,maskTexture:s,uniforms:n,frame:l,frameViewKey:c,windClock:d,landField:u,roadField:f}){const h=this.materialPass(o),m=h.material.uniforms;m.u_before.value=i,m.u_mask.value=s;const p=m.u_intensity.value;p.fill(0);for(const x of r)p[SURFACE_IDS[x]]=n.intensities[x];m.u_wind_clock.value=d,m.u_wind.value=n.wind,m.u_sun.value=n.sun,m.u_glint_color.value=n.glintColor,m.u_sky_color.value=n.skyColor,m.u_horizon_color.value=n.horizonColor,m.u_reflection.value=n.reflection,m.u_glint.value=n.glint,m.u_camera_altitude.value=l.camera[2]*l.metersPerMercator;const g=[e.drawingBufferWidth,e.drawingBufferHeight],v=Math.max(e.drawingBufferWidth/t.map.getCanvas().clientWidth,1),_=v>=1.5?2:1;m.u_viewport.value=g,m.u_device_pixel_ratio.value=v,m.u_pixels_per_shade.value=_;for(const x of surfaceKinds)m[`u_${x}_pattern`].value=n.patterns[x];m.u_roles.value=writeRoles(t.roles,n),m.u_land_field.value=u?.textures.field??null,m.u_openness.value=u?.textures.openness??null,m.u_land_field_fade.value=u?.fade??0,u&&(m.u_meters_from_clip.value=u.metersFromClip),m.u_road_field.value=f?.texture??null,m.u_road_field_fade.value=f?.fade??0;const{renderer:w}=t,y=shadedTargetOf(t,[Math.ceil(g[0]/_),Math.ceil(g[1]/_)]);w.setRenderTarget(y),w.state.buffers.depth.setMask(!0),w.clear(),this.drawGrids(t,o,h,l,c),w.setRenderTarget(null),composeOver(t,i,s,{intensities:p,shaded:y.texture,roles:m.u_roles.value,pixelsPerShade:_,overImagery:a})}drawGrids(e,t,o,r,a){const{onTerrain:i,tiles:s}=this.groundTilesOf(e.map,a),n=i?(e=>(e.terrainGrid??=(()=>{const e=129,t=/* @__PURE__ */new Int16Array(33282);for(let r=0;r<16641;r++)t[2*r]=r%e*64,t[2*r+1]=64*Math.floor(r/e);const o=[];for(let r=0;r<128;r++)for(let t=0;t<128;t++){const a=r*e+t;o.push(a,a+e,a+e+1,a,a+e+1,a+1)}return(new BufferGeometry).setAttribute("a_pos",new BufferAttribute(t,2)).setIndex(new BufferAttribute(new Uint16Array(o),1))})(),e.terrainGrid))(e):e.grid;o.material.depthTest=i,o.material.depthWrite=i,o.show(s.length,(e,a)=>{const{tile:i,terrain:n}=s[a];placeTile(e,o.material.uniforms,t,i,r,n)});for(const l of o.objects)l.geometry=n;drawPass(e.renderer,o.scene)}groundTilesOf(e,t){const o=this.groundTiles;if(o?.viewKey===t)return o.ground;const r=terrainTilesOf(e),a=r.length?{onTerrain:!0,tiles:r.map(t=>({tile:t,terrain:tileTerrainOf(e,t,r)}))}:{onTerrain:!1,tiles:e.coveringTiles({tileSize:512}).map(e=>({tile:e}))};return this.groundTiles={viewKey:t,ground:a},a}},NO_SURFACES=/* @__PURE__ */new Float32Array(SURFACE_ID_COUNT),composeOver=({renderer:e,composite:t},o,r,{intensities:a,shaded:i=null,roles:s=null,pixelsPerShade:n=1,overImagery:l=!1})=>{const c=t.material.uniforms;c.u_before.value=o,c.u_mask.value=r,c.u_shaded.value=i,c.u_roles.value=s,c.u_intensity.value=a,c.u_over_imagery.value=l?1:0,c.u_pixels_per_shade.value=n,drawPass(e,t)},shadedTargetOf=(e,t)=>(e.shaded??=fieldTarget(t,1,NearestFilter,!0),e.shaded.setSize(...t),e.shaded),rolesTexture=()=>{const e=new Float32Array(2*MATERIAL_ROLES.length*4),t=new DataTexture(e,MATERIAL_ROLES.length,2);return t.format=RGBAFormat,t.type=FloatType,{texture:t,data:e}},writeRoles=(e,t)=>{const{texture:o,data:r}=e;return e.writtenFrom===t||(e.writtenFrom=t,t.shades.forEach(({tint:e,toward:t},o)=>{r.set([...e,1],4*o),r.set(t,4*(MATERIAL_ROLES.length+o))}),o.needsUpdate=!0),o},placeTile=(e,t,o,r,a,i)=>{const s=projectionOf(o,r);setTileGround(e,t,s,i),t.u_ground_matrix.value.set(s.fallbackMatrix);const{origin:[n,l],camera:c,scale:d}=tilePlacementOf(r,a),{wind:u}=a;t.u_tile_origin.value=[MathUtils.euclideanModulo(n,4096),MathUtils.euclideanModulo(l,4096)],t.u_tile_origin_wind.value=[MathUtils.euclideanModulo(n*u[0]+l*u[1],4096),MathUtils.euclideanModulo(-n*u[1]+l*u[0],4096)],t.u_tile_scale.value=d,t.u_tile_camera.value=c},paintOf=(e,t)=>o=>e.getLayer(o)?e.getPaintProperty(o,t):void 0,woodlandColorIn=e=>colorWhere(e,"category","woodland"),styleFoliageOf=e=>{const t=paintOf(e,"fill-color");return{wild:woodlandColorIn(t(STYLE_LAYER_IDS.landcover)),tended:colorWhere(t(STYLE_LAYER_IDS.landuse),"group","outdoor")}},styleSurfaceColorsOf=e=>{const t=paintOf(e,"fill-color"),o=t(STYLE_LAYER_IDS.landcover),r=t(STYLE_LAYER_IDS.water);return{water:colorWhere(r,"category","lake"),ice:colorWhere(r,"category","glacier"),forest:woodlandColorIn(o),grass:colorWhere(o,"category","grassland"),scrub:colorWhere(o,"category","shrubland"),farmland:colorWhere(o,"category","agricultural"),sand:colorWhere(o,"category","sandy"),mud:colorWhere(o,"category","bareland"),paving:colorWhere(t(STYLE_LAYER_IDS.pedestrian),"category","pedestrian")}},keyColorOf=e=>`rgb(${16*e+8}, 255, 0)`,crossingOf=(e,[t,o],[r,a],i)=>{const s=(i-o)/(a-o);if(Array.isArray(e)&&"linear"===e[0])return t+s*(r-t);if(!Array.isArray(e)||"exponential"!==e[0]||"number"!=typeof e[1])return;const n=e[1];return 1===n?t+s*(r-t):t+Math.log1p(s*(n**(r-t)-1))/Math.log(n)},raisedStops=(e,t,o)=>{const r=[];for(let a=0;a<t.length;a+=2){const[i,s]=t.slice(a,a+2),[n,l]=a>0?t.slice(a-2,a):[],c="number"==typeof l&&"number"==typeof s&&(l-o)*(s-o)<0?crossingOf(e,[n,l],[i,s],o):void 0;void 0!==c&&r.push(c,o),r.push(i,atLeast(s,o))}return r},atLeast=(e,t)=>{if(void 0===e)return t;if(Array.isArray(e)&&"interpolate"===e[0]&&mentionsZoom(e[2])){const[,o,r,...a]=e;return["interpolate",o,r,...raisedStops(o,a,t)]}return wrapZoomFreeParts(e,e=>"number"==typeof e?Math.max(e,t):["max",e,t])??e},LEGACY_FILTER_OPERATORS=/* @__PURE__ */new Set(["==","!=","<",">","<=",">=","in","!in","has","!has"]),maskFilterOf=(e,t)=>{const o=Object.values(t.classes);return["all",...[(r=e,!Array.isArray(r)||"string"==typeof r[1]&&LEGACY_FILTER_OPERATORS.has(r[0])?void 0:e),o.includes(!0)?void 0:["any",...o]].filter(e=>void 0!==e)];var r},maskLayerOf=(e,t,{id:o,keyIds:r,opaque:a,minLineWidth:i})=>{if("fill"!==e.type&&"line"!==e.type||!("source"in e))return;const s={id:o,source:e.source,"source-layer":e["source-layer"],minzoom:e.minzoom,maxzoom:void 0===t.maxZoom?e.maxzoom:Math.min(t.maxZoom,e.maxzoom??24),filter:maskFilterOf(e.filter,t)},n=((e,t)=>{const o=Object.entries(e.classes),r=o.find(([,e])=>!0===e);return r?keyColorOf(t[r[0]]):["case",...o.flatMap(([e,o])=>[o,keyColorOf(t[e])]),"rgba(0, 0, 0, 0)"]})(t,r);if("fill"===e.type)return{...s,type:"fill",paint:{"fill-color":n,"fill-opacity":a?1:e.paint?.["fill-opacity"]??1,"fill-antialias":!1}};const{"line-width":l,"line-offset":c,"line-gap-width":d,"line-opacity":u}=e.paint??{},{"line-cap":f,"line-join":h}=e.layout??{},m=void 0===i?l:atLeast(l,i);return{...s,type:"line",layout:{...void 0!==f&&{"line-cap":f},...void 0!==h&&{"line-join":h}},paint:{"line-color":n,...void 0!==m&&{"line-width":m},...void 0!==c&&{"line-offset":c},...void 0!==d&&{"line-gap-width":d},"line-opacity":a?1:u??1}}},indexedInOrder=(e,t)=>{const o=new Map(e.map((e,t)=>[e,t]));return t.flatMap(e=>{const t=o.get(e.layerId);return void 0===t?[]:[{target:e,index:t}]}).sort((e,t)=>e.index-t.index)},presentInOrder=(e,t)=>indexedInOrder(e,t).map(({target:e})=>e),colorOf=e=>"string"==typeof e?e:void 0,kindsOf=e=>[...new Set(e.flatMap(e=>Object.keys(e.classes)))],materialMaskOf=e=>{const t=`gl-surfaces-mask-${e.layerId}`,o={id:t,keyIds:SURFACE_IDS,opaque:!1},r=kindsOf([e]);return{id:t,layerId:e.layerId,maskOf:t=>maskLayerOf(t,e,o),isDrawn:({intensities:e})=>r.some(t=>e[t]>0),followsVisibility:!0,moves:r.some(e=>MOVING_SURFACES.has(e))}},waterlineMaskOf=(e,t)=>{const o=`gl-surfaces-waterline-mask-${e}`,r={id:o,keyIds:SURFACE_IDS,opaque:!0};return{id:o,layerId:t.layerId,maskOf:e=>maskLayerOf(e,t,r),isDrawn:({intensities:e})=>e.sand>0,followsVisibility:!0,moves:!1}},treeMaskOf=e=>{const t=`gl-surfaces-trees-mask-${e.layerId}`,o={id:t,keyIds:TREE_MASK_IDS,opaque:!0,minLineWidth:2},r=Object.keys(e.classes).some(e=>"clear"!==e&&"track"!==e);return{id:t,layerId:e.layerId,maskOf:(t,{trees:r})=>{const a=maskLayerOf(t,e,o);return a&&{...a,minzoom:Math.max(a.minzoom??0,r.minZoom)}},isDrawn:({trees:e})=>e.visible,followsVisibility:Object.keys(e.classes).some(e=>"clear"!==e),moves:r}},GLSurfaces=class extends KnobConfigured{map;renderer;installedLayerIds=[];installedMasks=/* @__PURE__ */new Map;standIns=/* @__PURE__ */new Map;styleColors={};resolvedUniforms;removeStyleChangeHandler;removed=!1;onStyleData=()=>this.syncMasks();constructor(e,t={}){super(t),this.map=e,this.renderer=new SurfacesRenderer(()=>this.uniforms()),this.removeStyleChangeHandler=e.addStyleChangeHandler({onStyleChanged:()=>this.install()}),e.mapLibreMap.on("styledata",this.onStyleData),runWhenMapIsReady(this.map,()=>this.install())}applyConfig(e){const t=e.beforeLayerConfig!==this.config.beforeLayerConfig;this.config={...e},t&&this.map.mapReady?this.install():this.syncMasks(),this.map.mapLibreMap.triggerRepaint()}remove(){this.removed=!0,this.removeStyleChangeHandler(),this.mapLibreMap.off("styledata",this.onStyleData),this.removeLayers()}_knobValue(e){return this.lookValue(this.look(),e)}get mapLibreMap(){return this.map.mapLibreMap}context(){const e=this.map.mapReady?this.mapLibreMap.getSky():void 0,t="streetSatellite"===standardStyleIdOf(this.map.getStyleInput());return{theme:t?"light":this.map.styleLightDarkTheme,sky:{color:colorOf(e?.["sky-color"]),horizonColor:colorOf(e?.["horizon-color"])},light:getMapLight(this.map)??(t?SATELLITE_LIGHT:void 0),...this.styleColors}}look(){return resolveSurfacesLook(this.config,this.context())}uniforms(){const e=this.context(),t=JSON.stringify(e);return this.resolvedUniforms?.config===this.config&&this.resolvedUniforms.context===t||(this.resolvedUniforms={config:this.config,context:t,uniforms:surfaceUniformsOf(this.config,e)}),this.resolvedUniforms.uniforms}readStyleColors(){const e=this.mapLibreMap;this.styleColors={foliage:styleFoliageOf(e),surfaceColors:styleSurfaceColorsOf(e)}}install(){if(this.removed)return;const e=this.mapLibreMap;this.removeLayers(),this.readStyleColors();const t=e.getLayersOrder(),o=e.getStyle().layers,r=o.findLast(e=>"raster"===e.type&&this.map._isStyleLayer(e.id));this.renderer.imagerySourceId=r?.source,this.standIns=new Map((r?(e=>{const t=e.find(e=>"line"===e.type&&"roads"===e["source-layer"]);if(!t||!("source"in t)||!e.some(e=>"raster"===e.type))return[];const o=new Set(e.map(({id:e})=>e));return STAND_INS.filter(({id:e})=>!o.has(e)).map(e=>({...e,source:t.source}))})(o):[]).map(e=>[e.id,e])),this.installMaterialRuns(t);const a=standardStyleSurfaceTargets.filter(e=>"water"in e.classes&&this.standIns.has(e.layerId));if(r&&a.length){const e=a.map(e=>materialMaskOf({...e,classes:{water:e.classes.water}}));this.addRun(t[t.indexOf(r.id)+1],e,{pass:"materials",kinds:["water"],overImagery:!0})}const i=(e=>[...STAND_TARGETS,...e.filter(isClearingLine).map(({id:e})=>({layerId:e,classes:{track:!0}}))])(o),s=[...i.filter(e=>this.standIns.has(e.layerId)),...presentInOrder(t,i)];this.addRun(this.treesBeforeOf(e.getLayersOrder()),s.map(treeMaskOf),{pass:"trees"}),this.renderer.masksChanged(),this.syncMasks()}treesBeforeOf(e){const t=this.config.beforeLayerConfig??"lowestLabel";if("top"===t)return;const o=existingAnchorLayerID(this.mapLibreMap,mapStyleLayerIDs[t]);if(!o)return;let r=e.indexOf(o);for(;r>0&&this.isAddedOnTop(e[r-1]);)r--;return e[r]}isAddedOnTop(e){return!this.map._isStyleLayer(e)&&!this.installedLayerIds.includes(e)}removeLayers(){const e=this.mapLibreMap;for(const t of this.installedLayerIds)e.getLayer(t)&&e.removeLayer(t);this.installedLayerIds=[],this.installedMasks.clear(),this.renderer.runs=[]}installMaterialRuns(e){const t=presentInOrder(e,standardStyleSurfaceTargets);for(const o of((e,t)=>{const o=[];let r;for(const{target:a,index:i}of indexedInOrder(e,t)){const e=r&&i===r.index+1?r.run:[];0===e.length&&o.push(e),e.push(a),r={run:e,index:i}}return o})(e,standardStyleSurfaceTargets)){const r=o.at(-1).layerId,a=kindsOf(o);if(!a.length)continue;const i=o.filter(e=>kindsOf([e]).length).map(materialMaskOf),s=t.find(t=>t.layerId===STYLE_LAYER_IDS.water&&e.indexOf(t.layerId)>e.indexOf(r)),n=o.some(e=>"sand"in e.classes&&void 0===e.maxZoom);s&&n&&!a.includes("water")&&i.push(waterlineMaskOf(r,s)),this.addRun(e[e.indexOf(r)+1],i,{pass:"materials",kinds:a,lanes:o.some(e=>e.lanes)})}}addRun(e,t,o){const r=this.renderer.runs.length,a=t=>{this.mapLibreMap.addLayer(t,e),this.installedLayerIds.push(t.id)},i=this.uniforms();a(this.renderer.beforeLayer(`gl-surfaces-before-${r}`,r));const s=t.filter(({id:e,...t})=>{const o=this.originalOf(t.layerId),r=o&&t.maskOf(o,i);return!!r&&(a(r),this.installedMasks.set(e,t),!0)});a(this.renderer.compositeLayer(`gl-surfaces-composite-${r}`,r)),this.renderer.runs.push({...o,maskLayerIds:s.map(({id:e})=>e),movingMaskLayerIds:s.filter(({moves:e})=>e).map(({id:e})=>e)})}originalOf(e){return this.mapLibreMap.getLayer(e)?.serialize()??this.standIns.get(e)}syncMasks(){const e=this.mapLibreMap;this.map.mapReady&&this.readStyleColors();const t=this.uniforms();let o=!1;for(const[r,a]of this.installedMasks){const i=this.originalOf(a.layerId);if(!e.getLayer(r)||!i)continue;const s=a.followsVisibility?i.layout?.visibility??"visible":"visible",n=a.isDrawn(t)?s:"none";e.getLayoutProperty(r,"visibility")!==n&&(e.setLayoutProperty(r,"visibility",n),o=!0),o=this.followShape(r,a.maskOf(i,t))||o}o&&this.renderer.masksChanged(),this.syncRunLayers()}syncRunLayers(){const e=this.mapLibreMap;this.renderer.runs.forEach(({maskLayerIds:t},o)=>{const r=t.some(t=>e.getLayer(t)&&"none"!==e.getLayoutProperty(t,"visibility"))?"visible":"none";for(const a of[`gl-surfaces-before-${o}`,`gl-surfaces-composite-${o}`])e.getLayer(a)&&(e.getLayoutProperty(a,"visibility")??"visible")!==r&&e.setLayoutProperty(a,"visibility",r)})}followShape(e,t){if(!t)return!1;const o=this.mapLibreMap,r=o.getLayer(e);let a=!1;const[i,s]=[t.minzoom??0,t.maxzoom??24];!r||(r.minzoom??0)===i&&(r.maxzoom??24)===s||(o.setLayerZoomRange(e,i,s),a=!0);for(const[n,l]of Object.entries(t.paint??{}))sameJSON(l,o.getPaintProperty(e,n))||(o.setPaintProperty(e,n,l),a=!0);return sameJSON(t.filter,o.getFilter(e))||(o.setFilter(e,t.filter),a=!0),a}};export{Buildings3D,GLSurfaces,Landmarks3D,ModelsLayer,ModelsSource,buildLandmarksTileURL};