@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,193 @@
1
+ import HillshadeParsFragment from "@shaders/glsl/chunks/hillshade_pars_fragment.glsl";
2
+ import {
3
+ DataTexture,
4
+ Mesh,
5
+ OrthographicCamera,
6
+ PlaneGeometry,
7
+ Scene,
8
+ ShaderMaterial,
9
+ WebGLRenderer,
10
+ WebGLRenderTarget,
11
+ } from "three";
12
+
13
+ import type { HillshadeConfig } from "../event/HillshadeContext";
14
+
15
+ /**
16
+ * Generator for hillshade normal maps using offscreen rendering.
17
+ * Converts DEM textures into pre-computed normal maps to improve runtime performance.
18
+ */
19
+ export class HillshadeNormalMapGenerator {
20
+ private renderer: WebGLRenderer;
21
+ private scene: Scene;
22
+ private camera: OrthographicCamera;
23
+ private material: ShaderMaterial;
24
+ private quad: Mesh;
25
+
26
+ constructor(renderer: WebGLRenderer) {
27
+ this.renderer = renderer;
28
+
29
+ // Setup scene and camera for offscreen rendering
30
+ this.scene = new Scene();
31
+ this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
32
+
33
+ // Create shader material for normal computation
34
+ // Uses hillshade_pars_fragment.glsl for DEM decoding
35
+ this.material = new ShaderMaterial({
36
+ uniforms: {
37
+ uDemTexture: { value: null },
38
+ uTexelSize: { value: [0, 0] },
39
+ uMetersPerTexel: { value: 1.0 },
40
+ uOutputSize: { value: [0, 0] }, // Output render target size (content size without padding)
41
+ // Hillshade decoder uniforms (will be set per-generation)
42
+ uHillshadeRGBScaler: { value: [256, 1, 1 / 256] },
43
+ uHillshadeBoundary: { value: 0 },
44
+ uHillshadeMinOffset: { value: 0 },
45
+ uHillshadeMaxOffset: { value: 0 },
46
+ uHillshadeEpsilon: { value: 1.0 },
47
+ uHillshadeOffset: { value: -32768 },
48
+ },
49
+ vertexShader: `
50
+ void main() {
51
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
52
+ }
53
+ `,
54
+ fragmentShader: `
55
+ #define USE_HILLSHADE 1
56
+
57
+ uniform sampler2D uDemTexture;
58
+ uniform vec2 uTexelSize;
59
+ uniform float uMetersPerTexel;
60
+ uniform vec2 uOutputSize;
61
+
62
+ // Import DEM decoding and normal computation from hillshade shader
63
+ ${HillshadeParsFragment}
64
+
65
+ void main() {
66
+ ivec2 texSize = textureSize(uDemTexture, 0);
67
+
68
+ // Compute UV from gl_FragCoord using correct OUTPUT size (not DEM padded size)
69
+ // gl_FragCoord ranges from (0.5, 0.5) to (width-0.5, height-0.5)
70
+ // Map to UV [0,1] spanning pixel centers: (fragCoord - 0.5) / (size - 1)
71
+ vec2 pixelCoord = gl_FragCoord.xy - 0.5;
72
+ vec2 uv = pixelCoord / (uOutputSize - 1.0);
73
+
74
+ // Flip Y to match DEM texture coordinate system (top-down)
75
+ // gl_FragCoord is OpenGL coords (y=0 at bottom), but DEM texture is top-down (y=0 at top)
76
+ uv.y = 1.0 - uv.y;
77
+
78
+ // Check if this is valid terrain data
79
+ float testHeight = sampleHeightBilinear(uDemTexture, uv, texSize);
80
+
81
+ if (!isValidHeight(testHeight)) {
82
+ // Invalid data (ocean/no-data), output default upward normal (0, 0, 1)
83
+ // Store directly in RGB channels, mapped from [-1,1] to [0,1]
84
+ gl_FragColor = vec4(0.5, 0.5, 1.0, 1.0);
85
+ return;
86
+ }
87
+
88
+ // Compute normal from DEM
89
+ vec3 normal = computeNormalFromDEM(uDemTexture, uv, uTexelSize, uMetersPerTexel);
90
+
91
+ // Store normal directly in RGB channels (linear, can use hardware bilinear filtering)
92
+ // Map from [-1,1] to [0,1] for 8-bit storage
93
+ gl_FragColor = vec4(normal * 0.5 + 0.5, 1.0);
94
+ }
95
+ `,
96
+ });
97
+
98
+ // Create fullscreen quad
99
+ const geometry = new PlaneGeometry(2, 2);
100
+ this.quad = new Mesh(geometry, this.material);
101
+ this.scene.add(this.quad);
102
+ }
103
+
104
+ /**
105
+ * Render normal map to an existing RenderTarget (GPU-only, no readback)
106
+ * Used by HillshadeContext's RenderTarget pool to avoid GPU→CPU→GPU round-trip
107
+ * @param renderTarget - Target to render to (owned by HillshadeContext)
108
+ * @param demTexture - Source DEM texture (padded)
109
+ * @param metersPerTexel - Meters per texel for normal calculation
110
+ * @param hillshadeConfig - Hillshade decoder configuration
111
+ */
112
+ renderToTarget(
113
+ renderTarget: WebGLRenderTarget,
114
+ demTexture: DataTexture,
115
+ metersPerTexel: number,
116
+ hillshadeConfig: HillshadeConfig,
117
+ ): void {
118
+ const contentWidth = renderTarget.width;
119
+ const contentHeight = renderTarget.height;
120
+
121
+ // Calculate texel size for DEM sampling
122
+ const texelSize = 1.0 / (contentWidth - 1);
123
+
124
+ // Update shader uniforms
125
+ this.material.uniforms.uDemTexture.value = demTexture;
126
+ this.material.uniforms.uTexelSize.value = [texelSize, texelSize];
127
+ this.material.uniforms.uMetersPerTexel.value = metersPerTexel;
128
+ this.material.uniforms.uOutputSize.value = [contentWidth, contentHeight];
129
+
130
+ // Update hillshade decoder uniforms from Rust config
131
+ this.material.uniforms.uHillshadeRGBScaler.value =
132
+ hillshadeConfig.rgbScaler;
133
+ this.material.uniforms.uHillshadeBoundary.value = hillshadeConfig.boundary;
134
+ this.material.uniforms.uHillshadeMinOffset.value =
135
+ hillshadeConfig.minOffset;
136
+ this.material.uniforms.uHillshadeMaxOffset.value =
137
+ hillshadeConfig.maxOffset;
138
+ this.material.uniforms.uHillshadeEpsilon.value = hillshadeConfig.epsilon;
139
+ this.material.uniforms.uHillshadeOffset.value = hillshadeConfig.offset;
140
+
141
+ const currentRenderTarget = this.renderer.getRenderTarget();
142
+ this.renderer.setRenderTarget(renderTarget);
143
+ this.renderer.render(this.scene, this.camera);
144
+ this.renderer.setRenderTarget(currentRenderTarget);
145
+ }
146
+
147
+ /**
148
+ * Debug: Save normal map to file
149
+ * @param renderTarget - RenderTarget to read from
150
+ * @param filename - Output filename
151
+ */
152
+ dbgSaveNormalMap(renderTarget: WebGLRenderTarget, filename: string): void {
153
+ const width = renderTarget.width;
154
+ const height = renderTarget.height;
155
+ const pixels = new Uint8Array(width * height * 4);
156
+
157
+ this.renderer.readRenderTargetPixels(
158
+ renderTarget,
159
+ 0,
160
+ 0,
161
+ width,
162
+ height,
163
+ pixels,
164
+ );
165
+
166
+ // Create canvas and write pixels
167
+ const canvas = document.createElement("canvas");
168
+ canvas.width = width;
169
+ canvas.height = height;
170
+ const ctx = canvas.getContext("2d");
171
+ if (!ctx) return;
172
+
173
+ const imageData = ctx.createImageData(width, height);
174
+ imageData.data.set(pixels);
175
+ ctx.putImageData(imageData, 0, 0);
176
+
177
+ // Download
178
+ canvas.toBlob((blob) => {
179
+ if (!blob) return;
180
+ const url = URL.createObjectURL(blob);
181
+ const a = document.createElement("a");
182
+ a.href = url;
183
+ a.download = filename;
184
+ a.click();
185
+ URL.revokeObjectURL(url);
186
+ });
187
+ }
188
+
189
+ dispose(): void {
190
+ this.material.dispose();
191
+ this.quad.geometry.dispose();
192
+ }
193
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./arraysEqual";
2
+ export * from "./geometry";
3
+ export * from "./worker";
4
+ export * from "./replacer";
5
+ export * from "./screen";
6
+ export * from "./blendModes";
7
+ export * from "./object";
8
+ export * from "./textureFragmentIndex";
@@ -0,0 +1,14 @@
1
+ import { expect, it } from "vitest";
2
+
3
+ import { getExcludedKeys } from "./object";
4
+
5
+ it("should get all excluded keys", () => {
6
+ const obj = { type: "layer", material1: {}, material2: {} };
7
+ expect(getExcludedKeys(obj, ["type"])).toEqual(["material1", "material2"]);
8
+
9
+ expect(getExcludedKeys(obj, ["type", "material1"])).toEqual(["material2"]);
10
+
11
+ expect(getExcludedKeys(obj, ["type", "material1", "material2"])).toEqual([]);
12
+
13
+ expect(getExcludedKeys(obj, [])).toEqual(["type", "material1", "material2"]);
14
+ });
@@ -0,0 +1,7 @@
1
+ export const getExcludedKeys = <O extends object, K extends keyof O>(
2
+ object: O,
3
+ filters: K[],
4
+ ) => {
5
+ const keys = Object.keys(object) as (keyof O)[];
6
+ return keys.filter((k) => !filters.includes(k as K));
7
+ };
@@ -0,0 +1,42 @@
1
+ import { expect, test } from "vitest";
2
+
3
+ import { Replacer, createReplacer } from "./replacer";
4
+
5
+ test("Replacer should allow method chaining with side-effect free implementation", () => {
6
+ const source = "Hello, world! Hello, universe!";
7
+
8
+ // String replacements
9
+ const result1 = createReplacer(source)
10
+ .replace("world", "earth")
11
+ .replace("universe", "galaxy").source;
12
+ expect(result1).toBe("Hello, earth! Hello, galaxy!");
13
+
14
+ // RegExp replacements
15
+ const result2 = createReplacer(source)
16
+ .replace(/world/, "earth")
17
+ .replace(/universe/, "galaxy").source;
18
+ expect(result2).toBe("Hello, earth! Hello, galaxy!");
19
+
20
+ // Error case
21
+ expect(() =>
22
+ createReplacer("Hello, world!").replace(
23
+ "universe",
24
+ "galaxy",
25
+ "Custom Error",
26
+ ),
27
+ ).toThrow("Custom Error");
28
+
29
+ // Multiple replacements
30
+ const result3 = createReplacer(source)
31
+ .replace("Hello", "Hi")
32
+ .replace("world", "earth")
33
+ .replace("Hello", "Hi")
34
+ .replace("universe", "galaxy").source;
35
+ expect(result3).toBe("Hi, earth! Hi, galaxy!");
36
+
37
+ // Verify source property
38
+ const replacer = createReplacer("Hello, world!");
39
+ expect(replacer).toBeInstanceOf(Replacer);
40
+ expect(replacer.source).toBe("Hello, world!");
41
+ expect(replacer.source).toBe("Hello, world!");
42
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Replaces a substring in a string and throws an error if the replacement didn't occur.
3
+ * This is useful for shader code replacements where silent failures can be hard to debug.
4
+ *
5
+ * @param source - The source string to perform replacement on
6
+ * @param search - The substring or regex to search for
7
+ * @param replace - The string to replace the search substring with
8
+ * @param errorMessage - Optional custom error message
9
+ * @returns The string with replacements applied
10
+ * @throws Error if the search string/pattern was not found in the source
11
+ */
12
+ export function replaceOrThrow(
13
+ source: string,
14
+ search: string | RegExp,
15
+ replace: string,
16
+ errorMessage?: string,
17
+ ): string {
18
+ // Check if the pattern exists in the source
19
+ if (source.split(search).length === 1) {
20
+ throw new Error(
21
+ errorMessage ||
22
+ `Failed to replace "${search}" in shader code. The pattern was not found.`,
23
+ );
24
+ }
25
+
26
+ // Perform the replacement
27
+ return source.replace(search, replace);
28
+ }
29
+
30
+ /**
31
+ * A class for chaining string replacements with error detection.
32
+ * This allows for a more functional programming style with method chaining.
33
+ * This implementation is free of side effects - each method returns a new instance.
34
+ */
35
+ export class Replacer {
36
+ readonly source: string;
37
+
38
+ /**
39
+ * Creates a new Replacer instance
40
+ *
41
+ * @param source - The source string to perform replacements on
42
+ */
43
+ constructor(source: string) {
44
+ this.source = source;
45
+ }
46
+
47
+ /**
48
+ * Replaces a substring in the source string and throws an error if the replacement didn't occur.
49
+ * Returns a new Replacer instance with the updated string.
50
+ *
51
+ * @param search - The substring or regex to search for
52
+ * @param replace - The string to replace the search substring with
53
+ * @param errorMessage - Optional custom error message
54
+ * @returns A new Replacer instance with the updated string
55
+ * @throws Error if the search string/pattern was not found in the source
56
+ */
57
+ replace(
58
+ search: string | RegExp,
59
+ replace: string,
60
+ errorMessage?: string,
61
+ ): Replacer {
62
+ const newSource = replaceOrThrow(
63
+ this.source,
64
+ search,
65
+ replace,
66
+ errorMessage,
67
+ );
68
+ return new Replacer(newSource);
69
+ }
70
+
71
+ replaceWithCondition(
72
+ search: string | RegExp,
73
+ replace: string,
74
+ condition: boolean,
75
+ errorMessage?: string,
76
+ ) {
77
+ return condition ? this.replace(search, replace, errorMessage) : this;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Creates a new Replacer instance for chaining string replacements
83
+ *
84
+ * @param source - The source string to perform replacements on
85
+ * @returns A new Replacer instance
86
+ */
87
+ export function createReplacer(source: string): Replacer {
88
+ return new Replacer(source);
89
+ }
@@ -0,0 +1,29 @@
1
+ import type { Nullable, XYZ } from "@navaramap/core";
2
+ import { convertScreenToWorld } from "@navaramap/three_api";
3
+ import { Vector2 } from "three";
4
+
5
+ import type ThreeView from "../index";
6
+
7
+ export const convertScreenPos = (
8
+ view: ThreeView,
9
+ x: number,
10
+ y: number,
11
+ ): Nullable<XYZ> => {
12
+ if (!view.camera) {
13
+ console.error("View camera is not initialized.");
14
+ return;
15
+ }
16
+
17
+ const screenSize = view.screenSize;
18
+ const pixelRatio = view.pixelRatio;
19
+
20
+ const win = {
21
+ width: screenSize.x,
22
+ height: screenSize.y,
23
+ pixelRatio: pixelRatio,
24
+ };
25
+
26
+ const pos = convertScreenToWorld(win, view.camera.raw, new Vector2(x, y));
27
+
28
+ return pos;
29
+ };
@@ -0,0 +1,224 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+
3
+ import type { TileMesh } from "../mesh/tile";
4
+
5
+ import {
6
+ updateTextureFragmentIndex,
7
+ removeTextureFragmentIndex,
8
+ getTextureFragmentSlots,
9
+ type TextureSlot,
10
+ } from "./textureFragmentIndex";
11
+
12
+ function createTileMesh(id: string): TileMesh {
13
+ return { id } as unknown as TileMesh;
14
+ }
15
+
16
+ describe("textureFragmentIndex", () => {
17
+ let textureFragmentIndex: Map<string, Set<TextureSlot>>;
18
+ let tileMeshToFragmentIds: Map<TileMesh, Set<string>>;
19
+
20
+ beforeEach(() => {
21
+ textureFragmentIndex = new Map<string, Set<TextureSlot>>();
22
+ tileMeshToFragmentIds = new Map<TileMesh, Set<string>>();
23
+ });
24
+
25
+ function getSlotIndexes(fragmentId: string, tileMesh: TileMesh): number[] {
26
+ const slots = getTextureFragmentSlots(textureFragmentIndex, fragmentId);
27
+ if (!slots) return [];
28
+
29
+ return [...slots]
30
+ .filter((slot) => slot.tileMesh === tileMesh)
31
+ .map((slot) => slot.slotIndex)
32
+ .sort((a, b) => a - b);
33
+ }
34
+
35
+ it("indexes texture fragments for a tile mesh", () => {
36
+ const tileMesh = createTileMesh("tile-1");
37
+
38
+ updateTextureFragmentIndex(
39
+ textureFragmentIndex,
40
+ tileMeshToFragmentIds,
41
+ tileMesh,
42
+ ["frag-a", null, "frag-b"],
43
+ );
44
+
45
+ const fragASlots = getTextureFragmentSlots(textureFragmentIndex, "frag-a");
46
+ const fragBSlots = getTextureFragmentSlots(textureFragmentIndex, "frag-b");
47
+ const fragCSlots = getTextureFragmentSlots(textureFragmentIndex, "frag-c");
48
+
49
+ expect(fragASlots).toBeDefined();
50
+ expect(fragBSlots).toBeDefined();
51
+ expect(fragCSlots).toBeUndefined();
52
+
53
+ expect(getSlotIndexes("frag-a", tileMesh)).toEqual([0]);
54
+ expect(getSlotIndexes("frag-b", tileMesh)).toEqual([2]);
55
+
56
+ removeTextureFragmentIndex(
57
+ textureFragmentIndex,
58
+ tileMeshToFragmentIds,
59
+ tileMesh,
60
+ );
61
+ });
62
+
63
+ it("supports multiple tile meshes using the same fragment", () => {
64
+ const tileMesh1 = createTileMesh("tile-1");
65
+ const tileMesh2 = createTileMesh("tile-2");
66
+
67
+ updateTextureFragmentIndex(
68
+ textureFragmentIndex,
69
+ tileMeshToFragmentIds,
70
+ tileMesh1,
71
+ ["frag-shared"],
72
+ );
73
+ updateTextureFragmentIndex(
74
+ textureFragmentIndex,
75
+ tileMeshToFragmentIds,
76
+ tileMesh2,
77
+ ["frag-shared", "frag-x"],
78
+ );
79
+
80
+ const sharedSlots = getTextureFragmentSlots(
81
+ textureFragmentIndex,
82
+ "frag-shared",
83
+ );
84
+ expect(sharedSlots).toBeDefined();
85
+ expect(sharedSlots && [...sharedSlots].length).toBe(2);
86
+
87
+ expect(getSlotIndexes("frag-shared", tileMesh1)).toEqual([0]);
88
+ expect(getSlotIndexes("frag-shared", tileMesh2)).toEqual([0]);
89
+ expect(getSlotIndexes("frag-x", tileMesh2)).toEqual([1]);
90
+
91
+ removeTextureFragmentIndex(
92
+ textureFragmentIndex,
93
+ tileMeshToFragmentIds,
94
+ tileMesh1,
95
+ );
96
+ removeTextureFragmentIndex(
97
+ textureFragmentIndex,
98
+ tileMeshToFragmentIds,
99
+ tileMesh2,
100
+ );
101
+ });
102
+
103
+ it("removes previous index entries when updating the same tile mesh", () => {
104
+ const tileMesh = createTileMesh("tile-1");
105
+
106
+ updateTextureFragmentIndex(
107
+ textureFragmentIndex,
108
+ tileMeshToFragmentIds,
109
+ tileMesh,
110
+ ["frag-a", "frag-b"],
111
+ );
112
+ updateTextureFragmentIndex(
113
+ textureFragmentIndex,
114
+ tileMeshToFragmentIds,
115
+ tileMesh,
116
+ ["frag-c", null, "frag-b"],
117
+ );
118
+
119
+ expect(
120
+ getTextureFragmentSlots(textureFragmentIndex, "frag-a"),
121
+ ).toBeUndefined();
122
+ expect(getSlotIndexes("frag-b", tileMesh)).toEqual([2]);
123
+ expect(getSlotIndexes("frag-c", tileMesh)).toEqual([0]);
124
+
125
+ removeTextureFragmentIndex(
126
+ textureFragmentIndex,
127
+ tileMeshToFragmentIds,
128
+ tileMesh,
129
+ );
130
+ });
131
+
132
+ it("removes all slots for a tile mesh", () => {
133
+ const tileMesh = createTileMesh("tile-1");
134
+
135
+ updateTextureFragmentIndex(
136
+ textureFragmentIndex,
137
+ tileMeshToFragmentIds,
138
+ tileMesh,
139
+ ["frag-a", "frag-b"],
140
+ );
141
+ removeTextureFragmentIndex(
142
+ textureFragmentIndex,
143
+ tileMeshToFragmentIds,
144
+ tileMesh,
145
+ );
146
+
147
+ expect(
148
+ getTextureFragmentSlots(textureFragmentIndex, "frag-a"),
149
+ ).toBeUndefined();
150
+ expect(
151
+ getTextureFragmentSlots(textureFragmentIndex, "frag-b"),
152
+ ).toBeUndefined();
153
+ });
154
+
155
+ it("does nothing when removing a tile mesh that is not indexed", () => {
156
+ const tileMesh = createTileMesh("tile-1");
157
+
158
+ expect(() =>
159
+ removeTextureFragmentIndex(
160
+ textureFragmentIndex,
161
+ tileMeshToFragmentIds,
162
+ tileMesh,
163
+ ),
164
+ ).not.toThrow();
165
+ });
166
+
167
+ it("ignores null fragment ids", () => {
168
+ const tileMesh = createTileMesh("tile-1");
169
+
170
+ updateTextureFragmentIndex(
171
+ textureFragmentIndex,
172
+ tileMeshToFragmentIds,
173
+ tileMesh,
174
+ [null, null, "frag-a", null],
175
+ );
176
+
177
+ expect(
178
+ getTextureFragmentSlots(textureFragmentIndex, "frag-a"),
179
+ ).toBeDefined();
180
+ expect(getSlotIndexes("frag-a", tileMesh)).toEqual([2]);
181
+ expect(
182
+ getTextureFragmentSlots(textureFragmentIndex, "null"),
183
+ ).toBeUndefined();
184
+
185
+ removeTextureFragmentIndex(
186
+ textureFragmentIndex,
187
+ tileMeshToFragmentIds,
188
+ tileMesh,
189
+ );
190
+ });
191
+
192
+ it("deduplicates fragment ids in the bidirectional index but preserves slot entries", () => {
193
+ const tileMesh = createTileMesh("tile-1");
194
+
195
+ updateTextureFragmentIndex(
196
+ textureFragmentIndex,
197
+ tileMeshToFragmentIds,
198
+ tileMesh,
199
+ ["frag-a", "frag-a", "frag-b"],
200
+ );
201
+
202
+ expect(getSlotIndexes("frag-a", tileMesh)).toEqual([0, 1]);
203
+ expect(getSlotIndexes("frag-b", tileMesh)).toEqual([2]);
204
+
205
+ removeTextureFragmentIndex(
206
+ textureFragmentIndex,
207
+ tileMeshToFragmentIds,
208
+ tileMesh,
209
+ );
210
+
211
+ expect(
212
+ getTextureFragmentSlots(textureFragmentIndex, "frag-a"),
213
+ ).toBeUndefined();
214
+ expect(
215
+ getTextureFragmentSlots(textureFragmentIndex, "frag-b"),
216
+ ).toBeUndefined();
217
+ });
218
+
219
+ it("returns undefined for unknown fragment ids", () => {
220
+ expect(
221
+ getTextureFragmentSlots(textureFragmentIndex, "not-exists"),
222
+ ).toBeUndefined();
223
+ });
224
+ });