@navaramap/three 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/LICENSE +8 -0
  2. package/dist/assets/atmosphere/README.md +1 -0
  3. package/dist/assets/atmosphere/higher_order_scattering.bin +0 -0
  4. package/dist/assets/atmosphere/higher_order_scattering.exr +0 -0
  5. package/dist/assets/atmosphere/irradiance.bin +0 -0
  6. package/dist/assets/atmosphere/irradiance.exr +0 -0
  7. package/dist/assets/atmosphere/scattering.bin +0 -0
  8. package/dist/assets/atmosphere/scattering.exr +0 -0
  9. package/dist/assets/atmosphere/single_mie_scattering.bin +0 -0
  10. package/dist/assets/atmosphere/single_mie_scattering.exr +0 -0
  11. package/dist/assets/atmosphere/stars.bin +0 -0
  12. package/dist/assets/atmosphere/transmittance.bin +0 -0
  13. package/dist/assets/atmosphere/transmittance.exr +0 -0
  14. package/dist/assets/cloud/README.md +1 -0
  15. package/dist/assets/cloud/local_weather.png +0 -0
  16. package/dist/assets/cloud/shape.bin +1 -0
  17. package/dist/assets/cloud/shape_detail.bin +1 -0
  18. package/dist/assets/cloud/turbulence.png +0 -0
  19. package/dist/assets/fontWorker-CEJEfRpb.js +2 -0
  20. package/dist/assets/fontWorker-CEJEfRpb.js.map +1 -0
  21. package/dist/assets/index-BUB-ijMO.js +12 -0
  22. package/dist/assets/index-BUB-ijMO.js.map +1 -0
  23. package/dist/assets/navara_wasm_font_worker_bg-665OLxjy.wasm +0 -0
  24. package/dist/assets/navara_wasm_worker_bg-BXhKC5bE.wasm +0 -0
  25. package/dist/assets/noise/README.md +1 -0
  26. package/dist/assets/noise/stbn.bin +0 -0
  27. package/dist/assets/water/README.md +3 -0
  28. package/dist/assets/water/waternormals.jpg +0 -0
  29. package/dist/index.d.ts +10114 -0
  30. package/dist/index.js +34481 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/index.umd.cjs +6345 -0
  33. package/dist/index.umd.cjs.map +1 -0
  34. package/package.json +95 -0
  35. package/src/Color.ts +111 -0
  36. package/src/ShadowMapViewers.ts +49 -0
  37. package/src/atmosphere.test.ts +76 -0
  38. package/src/atmosphere.ts +364 -0
  39. package/src/bufferView.ts +90 -0
  40. package/src/camera.ts +182 -0
  41. package/src/concurrency.ts +15 -0
  42. package/src/constants/assets.ts +30 -0
  43. package/src/constants/decoder.ts +7 -0
  44. package/src/constants/index.ts +2 -0
  45. package/src/core/BaseDesc.ts +142 -0
  46. package/src/core/BaseHandle.ts +126 -0
  47. package/src/core/DescRegistry.ts +88 -0
  48. package/src/core/EffectDesc.ts +343 -0
  49. package/src/core/EffectDescRegistry.ts +31 -0
  50. package/src/core/InstancedMeshDesc.ts +413 -0
  51. package/src/core/LightDesc.ts +216 -0
  52. package/src/core/LightDescRegistry.ts +32 -0
  53. package/src/core/MeshDesc.ts +457 -0
  54. package/src/core/MeshDescRegistry.ts +32 -0
  55. package/src/core/MeshDescWithSelectiveEffect.ts +129 -0
  56. package/src/core/Registries.ts +59 -0
  57. package/src/core/SelectiveEffectRegistry.ts +90 -0
  58. package/src/core/ViewContext.ts +235 -0
  59. package/src/core/errors.ts +16 -0
  60. package/src/core/index.ts +50 -0
  61. package/src/device.ts +414 -0
  62. package/src/effects/CustomEffectPass.ts +28 -0
  63. package/src/effects/copy.ts +10 -0
  64. package/src/effects/effect.ts +87 -0
  65. package/src/effects/index.ts +4 -0
  66. package/src/effects/render.ts +10 -0
  67. package/src/evaluations/FeatureEvaluator.ts +529 -0
  68. package/src/evaluations/index.ts +1 -0
  69. package/src/event/HillshadeContext.test.ts +232 -0
  70. package/src/event/HillshadeContext.ts +299 -0
  71. package/src/event/context.ts +279 -0
  72. package/src/event/feature.ts +357 -0
  73. package/src/event/featureEvent.ts +81 -0
  74. package/src/event/features/billboard.ts +30 -0
  75. package/src/event/features/model.ts +192 -0
  76. package/src/event/features/modelGpuBytes.test.ts +69 -0
  77. package/src/event/features/modelGpuBytes.ts +87 -0
  78. package/src/event/features/point.ts +25 -0
  79. package/src/event/features/polygon.ts +23 -0
  80. package/src/event/features/polygonOutline.ts +19 -0
  81. package/src/event/features/polyline.ts +19 -0
  82. package/src/event/features/text.ts +71 -0
  83. package/src/event/hillshade.test.ts +842 -0
  84. package/src/event/hillshade.ts +588 -0
  85. package/src/event/index.ts +700 -0
  86. package/src/event/loaders.ts +53 -0
  87. package/src/event/tile.ts +19 -0
  88. package/src/event/worker.ts +999 -0
  89. package/src/event/workerTaskSettlement.test.ts +243 -0
  90. package/src/event/workerTaskSettlement.ts +128 -0
  91. package/src/inMemoryBufferStore.test.ts +60 -0
  92. package/src/inMemoryBufferStore.ts +67 -0
  93. package/src/index.iife.ts +11 -0
  94. package/src/index.ts +2556 -0
  95. package/src/input.ts +144 -0
  96. package/src/layer.ts +183 -0
  97. package/src/layers/effect/FinalCopyEffectDesc.ts +29 -0
  98. package/src/layers/effect/MRTPassEffectDesc.ts +105 -0
  99. package/src/layers/effect/README.md +9 -0
  100. package/src/layers/effect/SelectiveEffectDesc.ts +113 -0
  101. package/src/layers/effect/SkyEnvMapEffectDesc.ts +58 -0
  102. package/src/layers/effect/TransparentPassEffectDesc.ts +62 -0
  103. package/src/layers/effect/index.ts +5 -0
  104. package/src/layers/index.ts +1 -0
  105. package/src/layersManager.ts +63 -0
  106. package/src/light.ts +15 -0
  107. package/src/loaders/AbortableImageLoader.ts +203 -0
  108. package/src/loaders/AbortableTextureLoader.ts +74 -0
  109. package/src/loaders/index.ts +5 -0
  110. package/src/material/enhancer/DESIGN.md +300 -0
  111. package/src/material/enhancer/MaterialEnhancer.ts +112 -0
  112. package/src/material/enhancer/ShaderReplacer.test.ts +114 -0
  113. package/src/material/enhancer/ShaderReplacer.ts +97 -0
  114. package/src/material/enhancer/batchTexture.ts +8 -0
  115. package/src/material/enhancer/index.ts +46 -0
  116. package/src/material/enhancer/instancedSprite/index.ts +7 -0
  117. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.test.ts +214 -0
  118. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.ts +134 -0
  119. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/markers.ts +21 -0
  120. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/material.ts +32 -0
  121. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.test.ts +277 -0
  122. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.ts +151 -0
  123. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.test.ts +114 -0
  124. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.ts +49 -0
  125. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.test.ts +82 -0
  126. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.ts +80 -0
  127. package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/types.ts +146 -0
  128. package/src/material/enhancer/instancedSprite/instancedSpriteMaterialEnhancer.ts +105 -0
  129. package/src/material/enhancer/model/index.ts +25 -0
  130. package/src/material/enhancer/model/modelBaseEnhancer/index.test.ts +74 -0
  131. package/src/material/enhancer/model/modelBaseEnhancer/index.ts +110 -0
  132. package/src/material/enhancer/model/modelBaseEnhancer/markers.ts +27 -0
  133. package/src/material/enhancer/model/modelBaseEnhancer/material.test.ts +66 -0
  134. package/src/material/enhancer/model/modelBaseEnhancer/material.ts +44 -0
  135. package/src/material/enhancer/model/modelBaseEnhancer/mutates.test.ts +84 -0
  136. package/src/material/enhancer/model/modelBaseEnhancer/mutates.ts +47 -0
  137. package/src/material/enhancer/model/modelBaseEnhancer/shader.test.ts +24 -0
  138. package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +162 -0
  139. package/src/material/enhancer/model/modelBaseEnhancer/state.test.ts +103 -0
  140. package/src/material/enhancer/model/modelBaseEnhancer/state.ts +52 -0
  141. package/src/material/enhancer/model/modelBaseEnhancer/types.ts +89 -0
  142. package/src/material/enhancer/model/modelMaterialEnhancer.ts +91 -0
  143. package/src/material/enhancer/model/modelWaterEnhancer/index.test.ts +71 -0
  144. package/src/material/enhancer/model/modelWaterEnhancer/index.ts +175 -0
  145. package/src/material/enhancer/model/modelWaterEnhancer/material.test.ts +48 -0
  146. package/src/material/enhancer/model/modelWaterEnhancer/material.ts +25 -0
  147. package/src/material/enhancer/model/modelWaterEnhancer/mutates.test.ts +89 -0
  148. package/src/material/enhancer/model/modelWaterEnhancer/mutates.ts +89 -0
  149. package/src/material/enhancer/model/modelWaterEnhancer/shader.test.ts +34 -0
  150. package/src/material/enhancer/model/modelWaterEnhancer/shader.ts +111 -0
  151. package/src/material/enhancer/model/modelWaterEnhancer/state.test.ts +105 -0
  152. package/src/material/enhancer/model/modelWaterEnhancer/state.ts +59 -0
  153. package/src/material/enhancer/model/modelWaterEnhancer/types.ts +141 -0
  154. package/src/material/enhancer/model/pntsEnhancer/index.test.ts +96 -0
  155. package/src/material/enhancer/model/pntsEnhancer/index.ts +82 -0
  156. package/src/material/enhancer/model/pntsEnhancer/markers.ts +6 -0
  157. package/src/material/enhancer/model/pntsEnhancer/material.test.ts +37 -0
  158. package/src/material/enhancer/model/pntsEnhancer/material.ts +21 -0
  159. package/src/material/enhancer/model/pntsEnhancer/mutates.test.ts +80 -0
  160. package/src/material/enhancer/model/pntsEnhancer/mutates.ts +29 -0
  161. package/src/material/enhancer/model/pntsEnhancer/shader.test.ts +32 -0
  162. package/src/material/enhancer/model/pntsEnhancer/shader.ts +56 -0
  163. package/src/material/enhancer/model/pntsEnhancer/state.test.ts +87 -0
  164. package/src/material/enhancer/model/pntsEnhancer/state.ts +29 -0
  165. package/src/material/enhancer/model/pntsEnhancer/types.ts +38 -0
  166. package/src/material/enhancer/polygon/index.ts +22 -0
  167. package/src/material/enhancer/polygon/polygonBaseEnhancer/index.test.ts +101 -0
  168. package/src/material/enhancer/polygon/polygonBaseEnhancer/index.ts +130 -0
  169. package/src/material/enhancer/polygon/polygonBaseEnhancer/markers.ts +23 -0
  170. package/src/material/enhancer/polygon/polygonBaseEnhancer/material.test.ts +19 -0
  171. package/src/material/enhancer/polygon/polygonBaseEnhancer/material.ts +38 -0
  172. package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.test.ts +75 -0
  173. package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +122 -0
  174. package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.test.ts +25 -0
  175. package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +249 -0
  176. package/src/material/enhancer/polygon/polygonBaseEnhancer/state.test.ts +102 -0
  177. package/src/material/enhancer/polygon/polygonBaseEnhancer/state.ts +92 -0
  178. package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +150 -0
  179. package/src/material/enhancer/polygon/polygonMaterialEnhancer.ts +97 -0
  180. package/src/material/enhancer/polygon/polygonWaterEnhancer/index.test.ts +72 -0
  181. package/src/material/enhancer/polygon/polygonWaterEnhancer/index.ts +164 -0
  182. package/src/material/enhancer/polygon/polygonWaterEnhancer/material.test.ts +48 -0
  183. package/src/material/enhancer/polygon/polygonWaterEnhancer/material.ts +35 -0
  184. package/src/material/enhancer/polygon/polygonWaterEnhancer/mutates.ts +61 -0
  185. package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.test.ts +34 -0
  186. package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.ts +96 -0
  187. package/src/material/enhancer/polygon/polygonWaterEnhancer/state.test.ts +98 -0
  188. package/src/material/enhancer/polygon/polygonWaterEnhancer/state.ts +57 -0
  189. package/src/material/enhancer/polygon/polygonWaterEnhancer/types.ts +115 -0
  190. package/src/material/enhancer/polyline/index.ts +7 -0
  191. package/src/material/enhancer/polyline/polylineBaseEnhancer/index.test.ts +157 -0
  192. package/src/material/enhancer/polyline/polylineBaseEnhancer/index.ts +154 -0
  193. package/src/material/enhancer/polyline/polylineBaseEnhancer/markers.ts +19 -0
  194. package/src/material/enhancer/polyline/polylineBaseEnhancer/material.test.ts +42 -0
  195. package/src/material/enhancer/polyline/polylineBaseEnhancer/material.ts +38 -0
  196. package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.test.ts +120 -0
  197. package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.ts +169 -0
  198. package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.test.ts +67 -0
  199. package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.ts +75 -0
  200. package/src/material/enhancer/polyline/polylineBaseEnhancer/state.test.ts +55 -0
  201. package/src/material/enhancer/polyline/polylineBaseEnhancer/state.ts +91 -0
  202. package/src/material/enhancer/polyline/polylineBaseEnhancer/types.ts +170 -0
  203. package/src/material/enhancer/polyline/polylineMaterialEnhancer.ts +102 -0
  204. package/src/material/enhancer/sdfText/index.ts +7 -0
  205. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/index.ts +125 -0
  206. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/markers.ts +19 -0
  207. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.test.ts +35 -0
  208. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.ts +32 -0
  209. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.test.ts +381 -0
  210. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +232 -0
  211. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.ts +36 -0
  212. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.test.ts +118 -0
  213. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.ts +107 -0
  214. package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +184 -0
  215. package/src/material/enhancer/sdfText/sdfTextMaterialEnhancer.ts +100 -0
  216. package/src/material/enhancer/shadowMap/index.ts +7 -0
  217. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/index.ts +97 -0
  218. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/markers.ts +10 -0
  219. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/material.ts +31 -0
  220. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/mutates.ts +8 -0
  221. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.test.ts +17 -0
  222. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.ts +53 -0
  223. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/state.ts +17 -0
  224. package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/types.ts +26 -0
  225. package/src/material/enhancer/test-utils/shaderCompatibility.ts +124 -0
  226. package/src/material/enhancer/tileComposite/compose.test.ts +95 -0
  227. package/src/material/enhancer/tileComposite/compose.ts +112 -0
  228. package/src/material/enhancer/tileComposite/index.ts +23 -0
  229. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/index.ts +11 -0
  230. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +132 -0
  231. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/shader.ts +245 -0
  232. package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/types.ts +43 -0
  233. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/index.ts +29 -0
  234. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/mutates.ts +68 -0
  235. package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/shader.ts +24 -0
  236. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/index.ts +29 -0
  237. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/mutates.ts +34 -0
  238. package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/shader.ts +36 -0
  239. package/src/material/enhancer/tileComposite/tileWaterEnhancer/index.ts +23 -0
  240. package/src/material/enhancer/tileComposite/tileWaterEnhancer/mutates.ts +23 -0
  241. package/src/material/enhancer/tileComposite/tileWaterEnhancer/shader.ts +8 -0
  242. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/index.ts +23 -0
  243. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/mutates.ts +34 -0
  244. package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/shader.ts +13 -0
  245. package/src/material/enhancer/tileComposite/types.ts +58 -0
  246. package/src/material/index.ts +3 -0
  247. package/src/material/macro/index.ts +1 -0
  248. package/src/material/macro/tileShader.test.ts +136 -0
  249. package/src/material/macro/tileShader.ts +287 -0
  250. package/src/material/overrideMaterialsForMRT.ts +439 -0
  251. package/src/material/selectiveEffectMaterialSetup.test.ts +52 -0
  252. package/src/material/selectiveEffectMaterialSetup.ts +53 -0
  253. package/src/material/types/index.ts +1 -0
  254. package/src/material/types/uniform.ts +1 -0
  255. package/src/mesh/DrapedMesh.ts +101 -0
  256. package/src/mesh/batchTexture.test.ts +646 -0
  257. package/src/mesh/batchTexture.ts +437 -0
  258. package/src/mesh/batchedFeature.ts +186 -0
  259. package/src/mesh/batchedSdfText.ts +484 -0
  260. package/src/mesh/featureMesh.ts +43 -0
  261. package/src/mesh/index.ts +16 -0
  262. package/src/mesh/instanced.ts +117 -0
  263. package/src/mesh/model.ts +483 -0
  264. package/src/mesh/pickableMesh.ts +55 -0
  265. package/src/mesh/pickableMeshWrapper.ts +529 -0
  266. package/src/mesh/polygon.ts +699 -0
  267. package/src/mesh/polygonOutline.ts +393 -0
  268. package/src/mesh/polyline.ts +523 -0
  269. package/src/mesh/releaseGeometryArrays.ts +57 -0
  270. package/src/mesh/rtcRteHelper.ts +211 -0
  271. package/src/mesh/sdfText.test.ts +200 -0
  272. package/src/mesh/sdfText.ts +1019 -0
  273. package/src/mesh/sprite/billboardAtlas.test.ts +177 -0
  274. package/src/mesh/sprite/billboardAtlas.ts +210 -0
  275. package/src/mesh/sprite/billboardAtlasImageLoader.ts +29 -0
  276. package/src/mesh/sprite/index.ts +1 -0
  277. package/src/mesh/sprite/instancedSprite.ts +694 -0
  278. package/src/mesh/tile.test.ts +393 -0
  279. package/src/mesh/tile.ts +1790 -0
  280. package/src/object3DEvent.ts +6 -0
  281. package/src/orchestrators/RenderPassOrchestrator.ts +147 -0
  282. package/src/orchestrators/index.ts +1 -0
  283. package/src/passes/AllDepthCopyPass.ts +165 -0
  284. package/src/passes/CustomRenderPass.ts +279 -0
  285. package/src/passes/NormalCopyPass.ts +125 -0
  286. package/src/passes/RenderTargetCopyPass.ts +91 -0
  287. package/src/passes/SkyEnvMapPass.ts +58 -0
  288. package/src/passes/index.ts +5 -0
  289. package/src/pick/pickHelper.ts +273 -0
  290. package/src/pick/pickTerrain.ts +254 -0
  291. package/src/plugins/AttributionPlugin/AttributionPlugin.test.ts +210 -0
  292. package/src/plugins/AttributionPlugin/attribution.test.ts +225 -0
  293. package/src/plugins/AttributionPlugin/attribution.ts +355 -0
  294. package/src/plugins/AttributionPlugin/attributionStyles.ts +163 -0
  295. package/src/plugins/AttributionPlugin/index.ts +702 -0
  296. package/src/plugins/index.ts +1 -0
  297. package/src/quality.ts +1 -0
  298. package/src/renderOrder.ts +3 -0
  299. package/src/scene.test.ts +164 -0
  300. package/src/scene.ts +127 -0
  301. package/src/shaders/index.ts +1 -0
  302. package/src/solar.test.ts +81 -0
  303. package/src/solar.ts +101 -0
  304. package/src/source.ts +80 -0
  305. package/src/stats.ts +102 -0
  306. package/src/tasks/computeVertexNormalsAsync.ts +15 -0
  307. package/src/tasks/constructPolygonBatchedFeature.ts +34 -0
  308. package/src/tasks/constructPolylineBatchedFeature.ts +27 -0
  309. package/src/tasks/constructQuantizedMeshTerrainMesh.ts +24 -0
  310. package/src/tasks/constructTerrainMesh.ts +25 -0
  311. package/src/tasks/getImageDataFromBlob.ts +13 -0
  312. package/src/tasks/getImageDataFromImageBitmap.ts +12 -0
  313. package/src/tasks/parseMvtTile.ts +22 -0
  314. package/src/tasks/queueTask.ts +19 -0
  315. package/src/tasks/toCreasedNormalsAsync.ts +18 -0
  316. package/src/tasks/upsampleQuantizedMeshTerrainMesh.ts +44 -0
  317. package/src/tasks/upsampleTerrainMesh.ts +39 -0
  318. package/src/texture.ts +19 -0
  319. package/src/textures.ts +13 -0
  320. package/src/tileTexture/CompositeShader.snapshot.test.ts +59 -0
  321. package/src/tileTexture/CompositeShader.test.ts +168 -0
  322. package/src/tileTexture/CompositeShader.ts +53 -0
  323. package/src/tileTexture/SlotPlanner.test.ts +105 -0
  324. package/src/tileTexture/SlotPlanner.ts +102 -0
  325. package/src/tileTexture/TileTextureCache.test.ts +227 -0
  326. package/src/tileTexture/TileTextureCache.ts +192 -0
  327. package/src/tileTexture/TileTextureCompositor.test.ts +260 -0
  328. package/src/tileTexture/TileTextureCompositor.ts +421 -0
  329. package/src/tileTexture/__snapshots__/CompositeShader.snapshot.test.ts.snap +2649 -0
  330. package/src/tileTexture/index.ts +8 -0
  331. package/src/tileTexture/types.ts +150 -0
  332. package/src/type/index.ts +261 -0
  333. package/src/uniforms.ts +20 -0
  334. package/src/utils/arraysEqual.ts +9 -0
  335. package/src/utils/blendModes.ts +80 -0
  336. package/src/utils/geometry.ts +53 -0
  337. package/src/utils/hillshadeNormalMapGenerator.ts +193 -0
  338. package/src/utils/index.ts +8 -0
  339. package/src/utils/object.test.ts +14 -0
  340. package/src/utils/object.ts +7 -0
  341. package/src/utils/replacer.test.ts +42 -0
  342. package/src/utils/replacer.ts +89 -0
  343. package/src/utils/screen.ts +29 -0
  344. package/src/utils/textureFragmentIndex.test.ts +224 -0
  345. package/src/utils/textureFragmentIndex.ts +97 -0
  346. package/src/utils/worker.ts +3 -0
  347. package/src/vite-env.d.ts +2 -0
  348. package/src/worker/index.ts +13 -0
  349. package/src/worker/tasks/computeVertexNormals.ts +15 -0
  350. package/src/worker/tasks/toCreasedNormals.ts +22 -0
@@ -0,0 +1,245 @@
1
+ import type {
2
+ CompositeShaderContributions,
3
+ CompositeSlotContext,
4
+ } from "./types";
5
+
6
+ /**
7
+ * Per-slot marker comment, used by unit tests to assert that a given compact
8
+ * slot maps to the expected absolute slot + region. Exported so tests build
9
+ * the same string the shader emits — single source of truth for the format.
10
+ */
11
+ export const compositeSlotMarker = (
12
+ compactSlot: number,
13
+ absoluteSlot: number,
14
+ isVector: boolean,
15
+ ): string =>
16
+ `// ---- compact slot ${compactSlot} (absolute slot ${absoluteSlot}, ${isVector ? "vector" : "raster"}) ----`;
17
+
18
+ /**
19
+ * True only in vitest runs (Vite sets MODE="test"). Gates injection of
20
+ * `compositeSlotMarker` comments into the generated shader so production
21
+ * builds (MODE="development" | "production" | undefined for non-Vite
22
+ * consumers) carry no debug comments at all.
23
+ */
24
+ const EMIT_SHADER_DEBUG_COMMENTS = import.meta.env?.MODE === "test";
25
+
26
+ const emitSlotMarker = (
27
+ compactSlot: number,
28
+ absoluteSlot: number,
29
+ isVector: boolean,
30
+ ): string =>
31
+ EMIT_SHADER_DEBUG_COMMENTS
32
+ ? ` ${compositeSlotMarker(compactSlot, absoluteSlot, isVector)}`
33
+ : "";
34
+
35
+ /**
36
+ * Default raster sampler: a straight texture fetch tinted by the per-slot color.
37
+ * Composite layer enhancers can override this via
38
+ * `CompositeShaderContributions.sampleProducer` (e.g. the elevation heatmap).
39
+ */
40
+ const defaultRasterSampleProducer = ({ k }: CompositeSlotContext): string => `
41
+ vec4 texColor${k} = texture2D(uTextures[${k}], texUv${k}) * vec4(uColors[${k}], 1.0);`;
42
+
43
+ /**
44
+ * Build the composite-pass fragment shader skeleton, driving the per-slot loop
45
+ * and wiring in feature contributions from the composed layer enhancers.
46
+ *
47
+ * The base owns:
48
+ * - the `main()` scaffold + the standard local accumulators,
49
+ * - the core per-slot uniforms (shows/colors/opacities/textures/uv),
50
+ * - the compact→absolute slot mapping (baked into `winningSlot`),
51
+ * - the alpha-over blend and the MRT output writes.
52
+ *
53
+ * Everything feature-specific (hillshade, elevation heatmap, water, watermask)
54
+ * flows in through `contributions`, so the skeleton stays expression-agnostic.
55
+ *
56
+ * MRT outputs (WebGL2 layout(location=…)):
57
+ * 0: colorBuffer — composited diffuse (RGBA)
58
+ * 1: attrBuffer — packed material attrs (RGBA8):
59
+ * r = isWater, g = isTexturized, b = 0,
60
+ * a = (winSlot + 1) / 255 — 0 means no winner
61
+ * 2: normalBuffer — hillshade normal in [0,1]; .a = 1 when present, 0 when not.
62
+ */
63
+ export function buildCompositeFragmentShader(
64
+ rasterCount: number,
65
+ vectorCount: number,
66
+ texturizedSceneIndexFrom: number,
67
+ contributions: CompositeShaderContributions,
68
+ ): string {
69
+ const numTextures = rasterCount + vectorCount;
70
+
71
+ // Per-slot uniform arrays are elided when numTextures === 0 — GLSL forbids
72
+ // zero-length arrays (`uniform int x[0];` fails to compile). Watermask-only
73
+ // tiles (no raster + no vector layers, but a quantized-mesh watermask) still
74
+ // need to run the shader so the watermask sample reaches attr.r.
75
+ const slotUniforms =
76
+ numTextures > 0
77
+ ? `
78
+ uniform int uShows[${numTextures}];
79
+ uniform vec3 uColors[${numTextures}];
80
+ uniform float uOpacities[${numTextures}];
81
+ uniform sampler2D uTextures[${numTextures}];
82
+ uniform vec2 uLayerUvOffset[${numTextures}];
83
+ uniform vec2 uLayerUvScale[${numTextures}];
84
+ uniform int uReproject[${numTextures}];
85
+ uniform vec2 uReprojectTerrainLat[${numTextures}];
86
+ // CPU-precomputed per-slot reprojection constants (see mutates.ts):
87
+ // .xy = (mRs, mDen) — source tile's Mercator band start + span,
88
+ // .z = clamp-to-top-edge flag, .w = clamp-to-bottom-edge flag (polar cap).
89
+ uniform vec4 uReprojectMerc[${numTextures}];
90
+ ${contributions.slotUniformDecls}
91
+ `
92
+ : "";
93
+
94
+ const declUniforms = `
95
+ ${slotUniforms}
96
+ ${contributions.globalUniformDecls}
97
+ `;
98
+
99
+ const sampleProducer =
100
+ contributions.sampleProducer ?? defaultRasterSampleProducer;
101
+
102
+ // For each compact slot k, decide texColor and (conditionally) update winning
103
+ // slot index + per-winner attrs. The absolute slot index is baked in as a
104
+ // GLSL int constant so the TileMesh main shader's per-slot uniform arrays
105
+ // remain addressable by `winIdx` (= attr.a decoded). Last-writer-wins: a later
106
+ // slot's opaque pixel overwrites the winner recorded by earlier slots.
107
+ const slotBlocks = Array.from({ length: numTextures }, (_, k) => {
108
+ const isVector = k >= rasterCount;
109
+ const absSlot = isVector ? texturizedSceneIndexFrom + (k - rasterCount) : k;
110
+ const isTexturizedConst = isVector ? "1.0" : "0.0";
111
+ const ctx: CompositeSlotContext = { k, absSlot, isVector };
112
+
113
+ // WebMercator-on-Geographic latitude reprojection. Applies to both raster
114
+ // (imagery) slots and baked-vector slots: a vector layer's render target is
115
+ // baked spanning the terrain tile's WebMercator extent, so the paste remaps
116
+ // the latitude axis the same way (identity when the slot doesn't reproject,
117
+ // i.e. WebMercator terrain, where uReproject[k] == 0 makes this a no-op).
118
+ //
119
+ // Reprojection (and therefore N:M sub-rect confinement) is the only path that
120
+ // can drive texUv outside [0,1], so both the transcendental math and the
121
+ // `inBounds` test live behind the `uReproject` branch — non-reprojecting slots
122
+ // keep texUv in [0,1] by construction and pay neither cost.
123
+ const reprojectBlock = `
124
+ if (uReproject[${k}] == 1) {
125
+ // Affine UV is correct in longitude but stretches latitude. Remap this
126
+ // fragment's latitude through Mercator so it samples the source correctly.
127
+ //
128
+ // The only per-fragment transcendental left is mLat: it depends solely on
129
+ // vUv.y and the (tile-wide, slot-invariant) terrain lat range, so it is
130
+ // identical for every reprojecting slot — computed once and reused. The
131
+ // per-slot source band (mRs, mDen) and polar-cap flags are constant per slot
132
+ // and precomputed on the CPU (see mutates.ts), so no log/tan runs per slot.
133
+ if (!gReprojMLatReady) {
134
+ float lat = uReprojectTerrainLat[${k}].x
135
+ + vUv.y * (uReprojectTerrainLat[${k}].y - uReprojectTerrainLat[${k}].x);
136
+ gReprojMLat = log(tan(PI * 0.25 + lat * 0.5));
137
+ gReprojMLatReady = true;
138
+ }
139
+ float mRs = uReprojectMerc[${k}].x;
140
+ float mDen = uReprojectMerc[${k}].y;
141
+ // Only reproject when the source's Mercator span is wide enough to be
142
+ // numerically safe. For deep/upsampled tiles the span shrinks to ~1e-6 while
143
+ // mLat/mRs are ~O(1), so (mLat-mRs)/(mRn-mRs) catastrophically cancels in
144
+ // float32 and produces vertical-stretch noise. There the Mercator correction
145
+ // is sub-pixel anyway, so the affine texUv.y is both correct and stable.
146
+ if (abs(mDen) > 1e-3) {
147
+ texUv${k}.y = (gReprojMLat - mRs) / mDen;
148
+ }
149
+ // Polar cap fill: WebMercator content stops at ±~85.05° but Geographic
150
+ // terrain reaches ±90°. When this slot is the band-edge source (its
151
+ // north/south edge sits on the WM limit), clamp the polar overshoot onto
152
+ // that edge texel so the last available source row stretches across the cap
153
+ // instead of being dropped by the in-bounds test below. Non-edge tiles keep
154
+ // the normal drop.
155
+ if (uReprojectMerc[${k}].z > 0.5) texUv${k}.y = min(texUv${k}.y, 1.0);
156
+ if (uReprojectMerc[${k}].w > 0.5) texUv${k}.y = max(texUv${k}.y, 0.0);
157
+ // Confine the slot to the sub-rect it actually covers. With N:M draping each
158
+ // source tile covers only part of the terrain tile; outside its [0,1] range
159
+ // the sampler would smear the edge texel across the rest, so drop it there.
160
+ inBounds${k} = step(0.0, texUv${k}.x) * step(texUv${k}.x, 1.0)
161
+ * step(0.0, texUv${k}.y) * step(texUv${k}.y, 1.0);
162
+ }`;
163
+
164
+ return `
165
+ ${emitSlotMarker(k, absSlot, isVector)}
166
+ if (uShows[${k}] == 1) {
167
+ vec2 texUv${k} = vUv * uLayerUvScale[${k}] + uLayerUvOffset[${k}];
168
+ // 1.0 unless the reproject branch below confines this slot to a sub-rect.
169
+ float inBounds${k} = 1.0;
170
+ ${reprojectBlock}
171
+ ${sampleProducer(ctx)}
172
+ ${contributions.perSlotPostSample(ctx)}
173
+ float alpha${k} = texColor${k}.a * uOpacities[${k}] * inBounds${k};
174
+ if (alpha${k} > 0.01) {
175
+ compositedColor = mix(compositedColor, vec4(texColor${k}.rgb, 1.0), alpha${k});
176
+ winningSlot = ${absSlot};
177
+ isTexturized = ${isTexturizedConst};
178
+ ${contributions.perSlotOnWinner(ctx)}
179
+ }
180
+ }`;
181
+ }).join("\n");
182
+
183
+ return `
184
+ precision highp float;
185
+ precision highp int;
186
+
187
+ #include <common>
188
+
189
+ varying vec2 vUv;
190
+
191
+ ${declUniforms}
192
+
193
+ ${contributions.includes}
194
+
195
+ layout(location = 0) out vec4 colorBuffer;
196
+ layout(location = 1) out vec4 attrBuffer;
197
+ layout(location = 2) out vec4 normalBuffer;
198
+
199
+ void main() {
200
+ vec4 compositedColor = vec4(0.0);
201
+ int winningSlot = -1;
202
+ float isWater = 0.0;
203
+ float isTexturized = 0.0;
204
+
205
+ vec3 hillshadeNormal = vec3(0.5, 0.5, 1.0); // neutral upward
206
+ bool hasHillshadeNormal = false;
207
+
208
+ // Shared WebMercator reprojection latitude for this fragment. The terrain lat
209
+ // range is tile-wide, so mLat is identical across every reprojecting slot —
210
+ // computed lazily on first use and reused by the rest (see reproject block).
211
+ float gReprojMLat = 0.0;
212
+ bool gReprojMLatReady = false;
213
+
214
+ ${slotBlocks}
215
+
216
+ ${contributions.postLoop}
217
+
218
+ colorBuffer = compositedColor;
219
+
220
+ // Attr.a packs the winning slot index as (idx+1)/255 — 0 means no winner.
221
+ // Main shader: int winIdx = int(round(attr.a * 255.0)) - 1.
222
+ attrBuffer = vec4(
223
+ isWater,
224
+ isTexturized,
225
+ 0.0,
226
+ float(winningSlot + 1) / 255.0
227
+ );
228
+
229
+ normalBuffer = vec4(hillshadeNormal, hasHillshadeNormal ? 1.0 : 0.0);
230
+ }
231
+ `;
232
+ }
233
+
234
+ /**
235
+ * Vertex shader for the composite fullscreen quad. `position` and `uv` are
236
+ * auto-injected by three.js for ShaderMaterial — declaring them here causes
237
+ * a redefinition error under glslVersion: GLSL3.
238
+ */
239
+ export const COMPOSITE_VERTEX_SHADER = `
240
+ varying vec2 vUv;
241
+ void main() {
242
+ vUv = uv;
243
+ gl_Position = vec4(position, 1.0);
244
+ }
245
+ `;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Per-compact-slot context handed to the shader-contribution hooks while the
3
+ * base enhancer unrolls the composite slot loop.
4
+ */
5
+ export type CompositeSlotContext = {
6
+ /** Compact slot index `[0, rasterCount + vectorCount)`. */
7
+ k: number;
8
+ /** Absolute slot index baked into `winningSlot` for the main shader. */
9
+ absSlot: number;
10
+ /** True when the slot lives in the vector region (≥ rasterCount). */
11
+ isVector: boolean;
12
+ };
13
+
14
+ /**
15
+ * GLSL contributions assembled by the composite layer enhancers and consumed by
16
+ * the base enhancer's skeleton builder. The base owns the `main()` scaffold, the
17
+ * MRT outputs, the core uniforms, and the per-slot loop driver; everything
18
+ * feature-specific arrives through these hooks so a new expression is a new
19
+ * enhancer rather than an edit threaded across the generator.
20
+ */
21
+ export type CompositeShaderContributions = {
22
+ /**
23
+ * Feature per-slot uniform declarations (sized at numTextures). Joined by the
24
+ * base inside the `numTextures > 0` guard alongside the core uniforms.
25
+ */
26
+ slotUniformDecls: string;
27
+ /** Slot-independent uniform declarations (e.g. the watermask sampler). */
28
+ globalUniformDecls: string;
29
+ /** GLSL chunks inlined before `main()` (e.g. the elevation decoder). */
30
+ includes: string;
31
+ /**
32
+ * Produces `vec4 texColor${k} = …;` for a slot. Mutually exclusive — the most
33
+ * specific contributor wins (elevation heatmap overrides the raster default).
34
+ * Omitted → the base's default raster sampler is used.
35
+ */
36
+ sampleProducer?: (ctx: CompositeSlotContext) => string;
37
+ /** Additive transform applied to `texColor${k}` after sampling (hillshade). */
38
+ perSlotPostSample: (ctx: CompositeSlotContext) => string;
39
+ /** Additive attr update when a slot wins the alpha-over blend (water). */
40
+ perSlotOnWinner: (ctx: CompositeSlotContext) => string;
41
+ /** GLSL injected after the slot loop (hillshade normal pass, watermask). */
42
+ postLoop: string;
43
+ };
@@ -0,0 +1,29 @@
1
+ import type { CompositeLayerEnhancer } from "../types";
2
+
3
+ import { createElevationMutates } from "./mutates";
4
+ import {
5
+ elevationIncludes,
6
+ elevationSampleProducer,
7
+ elevationSlotUniformDecls,
8
+ } from "./shader";
9
+
10
+ /**
11
+ * Elevation heatmap layers decode a DEM raster to a height and colorize it
12
+ * through the shared 1-D colormap. The decoder uniforms and colormap sampler
13
+ * are slot-independent; the decoder chunk is inlined via `includes`.
14
+ */
15
+ export function createTileElevationHeatmapEnhancer(
16
+ active: boolean,
17
+ ): CompositeLayerEnhancer | undefined {
18
+ if (!active) return undefined;
19
+ const mutates = createElevationMutates();
20
+ return {
21
+ defines: { USE_ELEVATION_HEATMAP: 1 },
22
+ slotUniformDecls: elevationSlotUniformDecls,
23
+ includes: elevationIncludes,
24
+ sampleProducer: elevationSampleProducer,
25
+ attachUniforms: mutates.attachUniforms,
26
+ bindSlot: mutates.bindSlot,
27
+ bindGlobal: mutates.bindGlobal,
28
+ };
29
+ }
@@ -0,0 +1,68 @@
1
+ import { Uniform, Vector3, Vector4, type Texture } from "three";
2
+
3
+ import type {
4
+ CompositeGlobals,
5
+ CompositeLayer,
6
+ } from "../../../../tileTexture/types";
7
+ import type { CompositeUniformTarget } from "../tileCompositeBaseEnhancer";
8
+
9
+ export type ElevationMutates = {
10
+ attachUniforms: (
11
+ target: CompositeUniformTarget,
12
+ numTextures: number,
13
+ placeholder: Texture,
14
+ ) => void;
15
+ bindSlot: (compactSlot: number, layer: CompositeLayer | undefined) => void;
16
+ bindGlobal: (globals: CompositeGlobals) => void;
17
+ };
18
+
19
+ /**
20
+ * Owns the elevation heatmap per-slot flag array plus the slot-independent
21
+ * colormap sampler and DEM decoder params.
22
+ */
23
+ export function createElevationMutates(): ElevationMutates {
24
+ const refs = {
25
+ uIsElevationHeatmaps: new Uniform<boolean[]>([]),
26
+ uColorMapTexture: new Uniform<Texture | null>(null),
27
+ uElevationRGBScaler: new Uniform(new Vector3()),
28
+ uElevationMinMaxHeightAndBoundary: new Uniform(new Vector3()),
29
+ uElevationMinMaxOffsetAndEpsilonAndOffset: new Uniform(new Vector4()),
30
+ uLogarithmic: new Uniform(false),
31
+ uLogBase: new Uniform(10),
32
+ uLogBoundary: new Uniform(10),
33
+ };
34
+ return {
35
+ attachUniforms: (target, numTextures, placeholder) => {
36
+ refs.uIsElevationHeatmaps.value = new Array<boolean>(numTextures).fill(
37
+ false,
38
+ );
39
+ refs.uColorMapTexture.value = placeholder;
40
+ target.uIsElevationHeatmaps = refs.uIsElevationHeatmaps;
41
+ target.uColorMapTexture = refs.uColorMapTexture;
42
+ target.uElevationRGBScaler = refs.uElevationRGBScaler;
43
+ target.uElevationMinMaxHeightAndBoundary =
44
+ refs.uElevationMinMaxHeightAndBoundary;
45
+ target.uElevationMinMaxOffsetAndEpsilonAndOffset =
46
+ refs.uElevationMinMaxOffsetAndEpsilonAndOffset;
47
+ target.uLogarithmic = refs.uLogarithmic;
48
+ target.uLogBase = refs.uLogBase;
49
+ target.uLogBoundary = refs.uLogBoundary;
50
+ },
51
+ bindSlot: (k, layer) => {
52
+ refs.uIsElevationHeatmaps.value[k] = layer?.kind === "elevationHeatmap";
53
+ },
54
+ bindGlobal: (globals) => {
55
+ refs.uColorMapTexture.value = globals.colorMapTexture;
56
+ refs.uElevationRGBScaler.value.copy(globals.elevationRGBScaler);
57
+ refs.uElevationMinMaxHeightAndBoundary.value.copy(
58
+ globals.elevationMinMaxHeightAndBoundary,
59
+ );
60
+ refs.uElevationMinMaxOffsetAndEpsilonAndOffset.value.copy(
61
+ globals.elevationMinMaxOffsetAndEpsilonAndOffset,
62
+ );
63
+ refs.uLogarithmic.value = globals.logarithmic;
64
+ refs.uLogBase.value = globals.logBase;
65
+ refs.uLogBoundary.value = globals.logBoundary;
66
+ },
67
+ };
68
+ }
@@ -0,0 +1,24 @@
1
+ import ElevationParsFragment from "@shaders/glsl/chunks/elevation_pars_fragment.glsl";
2
+
3
+ import type { CompositeSlotContext } from "../tileCompositeBaseEnhancer";
4
+
5
+ export const elevationSlotUniformDecls = (numTextures: number): string =>
6
+ `uniform bool uIsElevationHeatmaps[${numTextures}];`;
7
+
8
+ export const elevationIncludes = (): string => ElevationParsFragment;
9
+
10
+ /**
11
+ * Replaces the per-slot sampler with a DEM-decode + colormap lookup; non-heatmap
12
+ * slots fall back to the straight raster fetch in the else branch.
13
+ */
14
+ export const elevationSampleProducer = ({
15
+ k,
16
+ }: CompositeSlotContext): string => `
17
+ vec4 texColor${k};
18
+ if (uIsElevationHeatmaps[${k}]) {
19
+ ivec2 demTexSize = textureSize(uTextures[${k}], 0);
20
+ float normalized_h = sampleElevationBilinear(uTextures[${k}], texUv${k}, demTexSize);
21
+ texColor${k} = vec4(texture2D(uColorMapTexture, vec2(normalized_h, 0.5)).rgb, 1.0);
22
+ } else {
23
+ texColor${k} = texture2D(uTextures[${k}], texUv${k}) * vec4(uColors[${k}], 1.0);
24
+ }`;
@@ -0,0 +1,29 @@
1
+ import type { CompositeLayerEnhancer } from "../types";
2
+
3
+ import { createHillshadeMutates } from "./mutates";
4
+ import {
5
+ hillshadePerSlotPostSample,
6
+ hillshadePostLoop,
7
+ hillshadeSlotUniformDecls,
8
+ } from "./shader";
9
+
10
+ /**
11
+ * Hillshade layers carry a DEM-derived normal map. They contribute no color to
12
+ * the composite (their slot color is zeroed) but write a tangent-space normal
13
+ * into the atlas's normal attachment, which the TileMesh main shader rotates
14
+ * via its TBN.
15
+ */
16
+ export function createTileHillshadeEnhancer(
17
+ active: boolean,
18
+ ): CompositeLayerEnhancer | undefined {
19
+ if (!active) return undefined;
20
+ const mutates = createHillshadeMutates();
21
+ return {
22
+ slotUniformDecls: hillshadeSlotUniformDecls,
23
+ perSlotPostSample: hillshadePerSlotPostSample,
24
+ postLoop: hillshadePostLoop,
25
+ attachUniforms: mutates.attachUniforms,
26
+ bindSlot: mutates.bindSlot,
27
+ bindGlobal: mutates.bindGlobal,
28
+ };
29
+ }
@@ -0,0 +1,34 @@
1
+ import { Uniform } from "three";
2
+
3
+ import type {
4
+ CompositeGlobals,
5
+ CompositeLayer,
6
+ } from "../../../../tileTexture/types";
7
+ import type { CompositeUniformTarget } from "../tileCompositeBaseEnhancer";
8
+
9
+ export type HillshadeMutates = {
10
+ attachUniforms: (target: CompositeUniformTarget, numTextures: number) => void;
11
+ bindSlot: (compactSlot: number, layer: CompositeLayer | undefined) => void;
12
+ bindGlobal: (globals: CompositeGlobals) => void;
13
+ };
14
+
15
+ /** Owns the hillshade per-slot flag array + shared exaggeration uniform. */
16
+ export function createHillshadeMutates(): HillshadeMutates {
17
+ const refs = {
18
+ uIsHillshades: new Uniform<boolean[]>([]),
19
+ uHillshadeExaggeration: new Uniform(1.0),
20
+ };
21
+ return {
22
+ attachUniforms: (target, numTextures) => {
23
+ refs.uIsHillshades.value = new Array<boolean>(numTextures).fill(false);
24
+ target.uIsHillshades = refs.uIsHillshades;
25
+ target.uHillshadeExaggeration = refs.uHillshadeExaggeration;
26
+ },
27
+ bindSlot: (k, layer) => {
28
+ refs.uIsHillshades.value[k] = layer?.kind === "hillshade";
29
+ },
30
+ bindGlobal: (globals) => {
31
+ refs.uHillshadeExaggeration.value = globals.hillshadeExaggeration;
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,36 @@
1
+ import type { CompositeSlotContext } from "../tileCompositeBaseEnhancer";
2
+
3
+ export const hillshadeSlotUniformDecls = (numTextures: number): string =>
4
+ `uniform bool uIsHillshades[${numTextures}];
5
+ uniform float uHillshadeExaggeration;`;
6
+
7
+ /** Hillshade slots contribute no color — their data is a normal map. */
8
+ export const hillshadePerSlotPostSample = ({
9
+ k,
10
+ }: CompositeSlotContext): string => `
11
+ if (uIsHillshades[${k}]) {
12
+ texColor${k} = vec4(0.0);
13
+ }`;
14
+
15
+ /**
16
+ * After the slot loop, sample each hillshade slot's normal into the atlas's
17
+ * normal attachment — the last hillshade slot wins. The TileMesh main shader
18
+ * rotates the stored tangent-space normal via its TBN.
19
+ */
20
+ export const hillshadePostLoop = (numTextures: number): string =>
21
+ Array.from(
22
+ { length: numTextures },
23
+ (_, k) => `
24
+ if (uIsHillshades[${k}]) {
25
+ ivec2 normalMapSize${k} = textureSize(uTextures[${k}], 0);
26
+ if (normalMapSize${k}.x > 1 && normalMapSize${k}.y > 1) {
27
+ vec2 hillshadeUv${k} = clamp(vUv * uLayerUvScale[${k}] + uLayerUvOffset[${k}], vec2(0.0), vec2(1.0));
28
+ vec3 n${k} = texture2D(uTextures[${k}], hillshadeUv${k}).rgb * 2.0 - 1.0;
29
+ n${k} = normalize(n${k});
30
+ n${k}.xy *= uHillshadeExaggeration;
31
+ n${k} = normalize(n${k});
32
+ hillshadeNormal = n${k} * 0.5 + 0.5; // store in [0,1]
33
+ hasHillshadeNormal = true;
34
+ }
35
+ }`,
36
+ ).join("\n");
@@ -0,0 +1,23 @@
1
+ import type { CompositeLayerEnhancer } from "../types";
2
+
3
+ import { createWaterMutates } from "./mutates";
4
+ import { waterPerSlotOnWinner, waterSlotUniformDecls } from "./shader";
5
+
6
+ /**
7
+ * Water layers flag the winning slot's pixel as water (attr.r), which the
8
+ * TileMesh main shader turns into a specular reflection. Precision-sensitive
9
+ * water params (scale, speed, …) stay in the main shader's per-slot uniform
10
+ * arrays — only the boolean flag is baked into the atlas here.
11
+ */
12
+ export function createTileWaterEnhancer(
13
+ active: boolean,
14
+ ): CompositeLayerEnhancer | undefined {
15
+ if (!active) return undefined;
16
+ const mutates = createWaterMutates();
17
+ return {
18
+ slotUniformDecls: waterSlotUniformDecls,
19
+ perSlotOnWinner: waterPerSlotOnWinner,
20
+ attachUniforms: mutates.attachUniforms,
21
+ bindSlot: mutates.bindSlot,
22
+ };
23
+ }
@@ -0,0 +1,23 @@
1
+ import { Uniform } from "three";
2
+
3
+ import type { CompositeLayer } from "../../../../tileTexture/types";
4
+ import type { CompositeUniformTarget } from "../tileCompositeBaseEnhancer";
5
+
6
+ export type WaterMutates = {
7
+ attachUniforms: (target: CompositeUniformTarget, numTextures: number) => void;
8
+ bindSlot: (compactSlot: number, layer: CompositeLayer | undefined) => void;
9
+ };
10
+
11
+ /** Owns the per-slot water flag array. */
12
+ export function createWaterMutates(): WaterMutates {
13
+ const refs = { uWaters: new Uniform<boolean[]>([]) };
14
+ return {
15
+ attachUniforms: (target, numTextures) => {
16
+ refs.uWaters.value = new Array<boolean>(numTextures).fill(false);
17
+ target.uWaters = refs.uWaters;
18
+ },
19
+ bindSlot: (k, layer) => {
20
+ refs.uWaters.value[k] = layer?.kind === "raster" ? layer.water : false;
21
+ },
22
+ };
23
+ }
@@ -0,0 +1,8 @@
1
+ import type { CompositeSlotContext } from "../tileCompositeBaseEnhancer";
2
+
3
+ export const waterSlotUniformDecls = (numTextures: number): string =>
4
+ `uniform bool uWaters[${numTextures}];`;
5
+
6
+ /** Flag the winning slot's pixel as water (attr.r). */
7
+ export const waterPerSlotOnWinner = ({ k }: CompositeSlotContext): string => `
8
+ isWater = uWaters[${k}] ? 1.0 : 0.0;`;
@@ -0,0 +1,23 @@
1
+ import type { CompositeLayerEnhancer } from "../types";
2
+
3
+ import { createWatermaskMutates } from "./mutates";
4
+ import { watermaskGlobalUniformDecls, watermaskPostLoop } from "./shader";
5
+
6
+ /**
7
+ * Quantized-mesh watermask: a slot-independent single-channel texture sampled
8
+ * once after the slot loop. Contributes a global sampler, not a per-slot
9
+ * uniform, so a watermask-only tile (no raster/vector layers) still bakes water
10
+ * into the atlas.
11
+ */
12
+ export function createTileWatermaskEnhancer(
13
+ active: boolean,
14
+ ): CompositeLayerEnhancer | undefined {
15
+ if (!active) return undefined;
16
+ const mutates = createWatermaskMutates();
17
+ return {
18
+ globalUniformDecls: watermaskGlobalUniformDecls,
19
+ postLoop: watermaskPostLoop,
20
+ attachUniforms: mutates.attachUniforms,
21
+ bindGlobal: mutates.bindGlobal,
22
+ };
23
+ }
@@ -0,0 +1,34 @@
1
+ import { Uniform, type Texture } from "three";
2
+
3
+ import type { CompositeGlobals } from "../../../../tileTexture/types";
4
+ import type { CompositeUniformTarget } from "../tileCompositeBaseEnhancer";
5
+
6
+ export type WatermaskMutates = {
7
+ attachUniforms: (
8
+ target: CompositeUniformTarget,
9
+ numTextures: number,
10
+ placeholder: Texture,
11
+ ) => void;
12
+ bindGlobal: (globals: CompositeGlobals) => void;
13
+ };
14
+
15
+ /** Owns the slot-independent watermask sampler. */
16
+ export function createWatermaskMutates(): WatermaskMutates {
17
+ const refs = { uWatermask: new Uniform<Texture | null>(null) };
18
+ let placeholderTexture: Texture | null = null;
19
+ return {
20
+ attachUniforms: (target, _numTextures, placeholder) => {
21
+ // Initialised to the 1×1 placeholder (byte 0 → no water) so the sampler
22
+ // is valid before the first bindGlobal.
23
+ placeholderTexture = placeholder;
24
+ refs.uWatermask.value = placeholder;
25
+ target.uWatermask = refs.uWatermask;
26
+ },
27
+ bindGlobal: (globals) => {
28
+ // No watermask on this tile → fall back to the placeholder so the sampler
29
+ // stays valid (R=0 → step(0.5, 0)=0 → no water) and a stale texture from a
30
+ // prior tile on this shared material doesn't leak through.
31
+ refs.uWatermask.value = globals.watermask ?? placeholderTexture;
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,13 @@
1
+ export const watermaskGlobalUniformDecls = (): string =>
2
+ `uniform sampler2D uWatermask;`;
3
+
4
+ /**
5
+ * Sampled once after the slot loop and OR'd into isWater so it takes priority
6
+ * even when no per-slot water flag fired (e.g. open-ocean tiles with no
7
+ * raster/vector layers).
8
+ */
9
+ export const watermaskPostLoop = (): string => `
10
+ // Quantized-mesh watermask: 0 = land, 255 = water (per spec). Takes priority
11
+ // over per-slot uWaters — even if no winning slot flagged water, watermask
12
+ // can still mark this pixel as water. Threshold at 0.5 (byte > 127).
13
+ isWater = max(isWater, step(0.5, texture(uWatermask, vUv).r));`;