@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.
- package/LICENSE +8 -0
- package/dist/assets/atmosphere/README.md +1 -0
- package/dist/assets/atmosphere/higher_order_scattering.bin +0 -0
- package/dist/assets/atmosphere/higher_order_scattering.exr +0 -0
- package/dist/assets/atmosphere/irradiance.bin +0 -0
- package/dist/assets/atmosphere/irradiance.exr +0 -0
- package/dist/assets/atmosphere/scattering.bin +0 -0
- package/dist/assets/atmosphere/scattering.exr +0 -0
- package/dist/assets/atmosphere/single_mie_scattering.bin +0 -0
- package/dist/assets/atmosphere/single_mie_scattering.exr +0 -0
- package/dist/assets/atmosphere/stars.bin +0 -0
- package/dist/assets/atmosphere/transmittance.bin +0 -0
- package/dist/assets/atmosphere/transmittance.exr +0 -0
- package/dist/assets/cloud/README.md +1 -0
- package/dist/assets/cloud/local_weather.png +0 -0
- package/dist/assets/cloud/shape.bin +1 -0
- package/dist/assets/cloud/shape_detail.bin +1 -0
- package/dist/assets/cloud/turbulence.png +0 -0
- package/dist/assets/fontWorker-CEJEfRpb.js +2 -0
- package/dist/assets/fontWorker-CEJEfRpb.js.map +1 -0
- package/dist/assets/index-BUB-ijMO.js +12 -0
- package/dist/assets/index-BUB-ijMO.js.map +1 -0
- package/dist/assets/navara_wasm_font_worker_bg-665OLxjy.wasm +0 -0
- package/dist/assets/navara_wasm_worker_bg-BXhKC5bE.wasm +0 -0
- package/dist/assets/noise/README.md +1 -0
- package/dist/assets/noise/stbn.bin +0 -0
- package/dist/assets/water/README.md +3 -0
- package/dist/assets/water/waternormals.jpg +0 -0
- package/dist/index.d.ts +10114 -0
- package/dist/index.js +34481 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +6345 -0
- package/dist/index.umd.cjs.map +1 -0
- package/package.json +95 -0
- package/src/Color.ts +111 -0
- package/src/ShadowMapViewers.ts +49 -0
- package/src/atmosphere.test.ts +76 -0
- package/src/atmosphere.ts +364 -0
- package/src/bufferView.ts +90 -0
- package/src/camera.ts +182 -0
- package/src/concurrency.ts +15 -0
- package/src/constants/assets.ts +30 -0
- package/src/constants/decoder.ts +7 -0
- package/src/constants/index.ts +2 -0
- package/src/core/BaseDesc.ts +142 -0
- package/src/core/BaseHandle.ts +126 -0
- package/src/core/DescRegistry.ts +88 -0
- package/src/core/EffectDesc.ts +343 -0
- package/src/core/EffectDescRegistry.ts +31 -0
- package/src/core/InstancedMeshDesc.ts +413 -0
- package/src/core/LightDesc.ts +216 -0
- package/src/core/LightDescRegistry.ts +32 -0
- package/src/core/MeshDesc.ts +457 -0
- package/src/core/MeshDescRegistry.ts +32 -0
- package/src/core/MeshDescWithSelectiveEffect.ts +129 -0
- package/src/core/Registries.ts +59 -0
- package/src/core/SelectiveEffectRegistry.ts +90 -0
- package/src/core/ViewContext.ts +235 -0
- package/src/core/errors.ts +16 -0
- package/src/core/index.ts +50 -0
- package/src/device.ts +414 -0
- package/src/effects/CustomEffectPass.ts +28 -0
- package/src/effects/copy.ts +10 -0
- package/src/effects/effect.ts +87 -0
- package/src/effects/index.ts +4 -0
- package/src/effects/render.ts +10 -0
- package/src/evaluations/FeatureEvaluator.ts +529 -0
- package/src/evaluations/index.ts +1 -0
- package/src/event/HillshadeContext.test.ts +232 -0
- package/src/event/HillshadeContext.ts +299 -0
- package/src/event/context.ts +279 -0
- package/src/event/feature.ts +357 -0
- package/src/event/featureEvent.ts +81 -0
- package/src/event/features/billboard.ts +30 -0
- package/src/event/features/model.ts +192 -0
- package/src/event/features/modelGpuBytes.test.ts +69 -0
- package/src/event/features/modelGpuBytes.ts +87 -0
- package/src/event/features/point.ts +25 -0
- package/src/event/features/polygon.ts +23 -0
- package/src/event/features/polygonOutline.ts +19 -0
- package/src/event/features/polyline.ts +19 -0
- package/src/event/features/text.ts +71 -0
- package/src/event/hillshade.test.ts +842 -0
- package/src/event/hillshade.ts +588 -0
- package/src/event/index.ts +700 -0
- package/src/event/loaders.ts +53 -0
- package/src/event/tile.ts +19 -0
- package/src/event/worker.ts +999 -0
- package/src/event/workerTaskSettlement.test.ts +243 -0
- package/src/event/workerTaskSettlement.ts +128 -0
- package/src/inMemoryBufferStore.test.ts +60 -0
- package/src/inMemoryBufferStore.ts +67 -0
- package/src/index.iife.ts +11 -0
- package/src/index.ts +2556 -0
- package/src/input.ts +144 -0
- package/src/layer.ts +183 -0
- package/src/layers/effect/FinalCopyEffectDesc.ts +29 -0
- package/src/layers/effect/MRTPassEffectDesc.ts +105 -0
- package/src/layers/effect/README.md +9 -0
- package/src/layers/effect/SelectiveEffectDesc.ts +113 -0
- package/src/layers/effect/SkyEnvMapEffectDesc.ts +58 -0
- package/src/layers/effect/TransparentPassEffectDesc.ts +62 -0
- package/src/layers/effect/index.ts +5 -0
- package/src/layers/index.ts +1 -0
- package/src/layersManager.ts +63 -0
- package/src/light.ts +15 -0
- package/src/loaders/AbortableImageLoader.ts +203 -0
- package/src/loaders/AbortableTextureLoader.ts +74 -0
- package/src/loaders/index.ts +5 -0
- package/src/material/enhancer/DESIGN.md +300 -0
- package/src/material/enhancer/MaterialEnhancer.ts +112 -0
- package/src/material/enhancer/ShaderReplacer.test.ts +114 -0
- package/src/material/enhancer/ShaderReplacer.ts +97 -0
- package/src/material/enhancer/batchTexture.ts +8 -0
- package/src/material/enhancer/index.ts +46 -0
- package/src/material/enhancer/instancedSprite/index.ts +7 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.test.ts +214 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.ts +134 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/markers.ts +21 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/material.ts +32 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.test.ts +277 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.ts +151 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.test.ts +114 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.ts +49 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.test.ts +82 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.ts +80 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/types.ts +146 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteMaterialEnhancer.ts +105 -0
- package/src/material/enhancer/model/index.ts +25 -0
- package/src/material/enhancer/model/modelBaseEnhancer/index.test.ts +74 -0
- package/src/material/enhancer/model/modelBaseEnhancer/index.ts +110 -0
- package/src/material/enhancer/model/modelBaseEnhancer/markers.ts +27 -0
- package/src/material/enhancer/model/modelBaseEnhancer/material.test.ts +66 -0
- package/src/material/enhancer/model/modelBaseEnhancer/material.ts +44 -0
- package/src/material/enhancer/model/modelBaseEnhancer/mutates.test.ts +84 -0
- package/src/material/enhancer/model/modelBaseEnhancer/mutates.ts +47 -0
- package/src/material/enhancer/model/modelBaseEnhancer/shader.test.ts +24 -0
- package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +162 -0
- package/src/material/enhancer/model/modelBaseEnhancer/state.test.ts +103 -0
- package/src/material/enhancer/model/modelBaseEnhancer/state.ts +52 -0
- package/src/material/enhancer/model/modelBaseEnhancer/types.ts +89 -0
- package/src/material/enhancer/model/modelMaterialEnhancer.ts +91 -0
- package/src/material/enhancer/model/modelWaterEnhancer/index.test.ts +71 -0
- package/src/material/enhancer/model/modelWaterEnhancer/index.ts +175 -0
- package/src/material/enhancer/model/modelWaterEnhancer/material.test.ts +48 -0
- package/src/material/enhancer/model/modelWaterEnhancer/material.ts +25 -0
- package/src/material/enhancer/model/modelWaterEnhancer/mutates.test.ts +89 -0
- package/src/material/enhancer/model/modelWaterEnhancer/mutates.ts +89 -0
- package/src/material/enhancer/model/modelWaterEnhancer/shader.test.ts +34 -0
- package/src/material/enhancer/model/modelWaterEnhancer/shader.ts +111 -0
- package/src/material/enhancer/model/modelWaterEnhancer/state.test.ts +105 -0
- package/src/material/enhancer/model/modelWaterEnhancer/state.ts +59 -0
- package/src/material/enhancer/model/modelWaterEnhancer/types.ts +141 -0
- package/src/material/enhancer/model/pntsEnhancer/index.test.ts +96 -0
- package/src/material/enhancer/model/pntsEnhancer/index.ts +82 -0
- package/src/material/enhancer/model/pntsEnhancer/markers.ts +6 -0
- package/src/material/enhancer/model/pntsEnhancer/material.test.ts +37 -0
- package/src/material/enhancer/model/pntsEnhancer/material.ts +21 -0
- package/src/material/enhancer/model/pntsEnhancer/mutates.test.ts +80 -0
- package/src/material/enhancer/model/pntsEnhancer/mutates.ts +29 -0
- package/src/material/enhancer/model/pntsEnhancer/shader.test.ts +32 -0
- package/src/material/enhancer/model/pntsEnhancer/shader.ts +56 -0
- package/src/material/enhancer/model/pntsEnhancer/state.test.ts +87 -0
- package/src/material/enhancer/model/pntsEnhancer/state.ts +29 -0
- package/src/material/enhancer/model/pntsEnhancer/types.ts +38 -0
- package/src/material/enhancer/polygon/index.ts +22 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/index.test.ts +101 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/index.ts +130 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/markers.ts +23 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/material.test.ts +19 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/material.ts +38 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.test.ts +75 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +122 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.test.ts +25 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +249 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/state.test.ts +102 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/state.ts +92 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +150 -0
- package/src/material/enhancer/polygon/polygonMaterialEnhancer.ts +97 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/index.test.ts +72 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/index.ts +164 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/material.test.ts +48 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/material.ts +35 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/mutates.ts +61 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.test.ts +34 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.ts +96 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/state.test.ts +98 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/state.ts +57 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/types.ts +115 -0
- package/src/material/enhancer/polyline/index.ts +7 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/index.test.ts +157 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/index.ts +154 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/markers.ts +19 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/material.test.ts +42 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/material.ts +38 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.test.ts +120 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.ts +169 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.test.ts +67 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.ts +75 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/state.test.ts +55 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/state.ts +91 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/types.ts +170 -0
- package/src/material/enhancer/polyline/polylineMaterialEnhancer.ts +102 -0
- package/src/material/enhancer/sdfText/index.ts +7 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/index.ts +125 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/markers.ts +19 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.test.ts +35 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.ts +32 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.test.ts +381 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +232 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.ts +36 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.test.ts +118 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.ts +107 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +184 -0
- package/src/material/enhancer/sdfText/sdfTextMaterialEnhancer.ts +100 -0
- package/src/material/enhancer/shadowMap/index.ts +7 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/index.ts +97 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/markers.ts +10 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/material.ts +31 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/mutates.ts +8 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.test.ts +17 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.ts +53 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/state.ts +17 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/types.ts +26 -0
- package/src/material/enhancer/test-utils/shaderCompatibility.ts +124 -0
- package/src/material/enhancer/tileComposite/compose.test.ts +95 -0
- package/src/material/enhancer/tileComposite/compose.ts +112 -0
- package/src/material/enhancer/tileComposite/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/index.ts +11 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +132 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/shader.ts +245 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/types.ts +43 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/index.ts +29 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/mutates.ts +68 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/shader.ts +24 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/index.ts +29 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/mutates.ts +34 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/shader.ts +36 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/mutates.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/shader.ts +8 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/mutates.ts +34 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/shader.ts +13 -0
- package/src/material/enhancer/tileComposite/types.ts +58 -0
- package/src/material/index.ts +3 -0
- package/src/material/macro/index.ts +1 -0
- package/src/material/macro/tileShader.test.ts +136 -0
- package/src/material/macro/tileShader.ts +287 -0
- package/src/material/overrideMaterialsForMRT.ts +439 -0
- package/src/material/selectiveEffectMaterialSetup.test.ts +52 -0
- package/src/material/selectiveEffectMaterialSetup.ts +53 -0
- package/src/material/types/index.ts +1 -0
- package/src/material/types/uniform.ts +1 -0
- package/src/mesh/DrapedMesh.ts +101 -0
- package/src/mesh/batchTexture.test.ts +646 -0
- package/src/mesh/batchTexture.ts +437 -0
- package/src/mesh/batchedFeature.ts +186 -0
- package/src/mesh/batchedSdfText.ts +484 -0
- package/src/mesh/featureMesh.ts +43 -0
- package/src/mesh/index.ts +16 -0
- package/src/mesh/instanced.ts +117 -0
- package/src/mesh/model.ts +483 -0
- package/src/mesh/pickableMesh.ts +55 -0
- package/src/mesh/pickableMeshWrapper.ts +529 -0
- package/src/mesh/polygon.ts +699 -0
- package/src/mesh/polygonOutline.ts +393 -0
- package/src/mesh/polyline.ts +523 -0
- package/src/mesh/releaseGeometryArrays.ts +57 -0
- package/src/mesh/rtcRteHelper.ts +211 -0
- package/src/mesh/sdfText.test.ts +200 -0
- package/src/mesh/sdfText.ts +1019 -0
- package/src/mesh/sprite/billboardAtlas.test.ts +177 -0
- package/src/mesh/sprite/billboardAtlas.ts +210 -0
- package/src/mesh/sprite/billboardAtlasImageLoader.ts +29 -0
- package/src/mesh/sprite/index.ts +1 -0
- package/src/mesh/sprite/instancedSprite.ts +694 -0
- package/src/mesh/tile.test.ts +393 -0
- package/src/mesh/tile.ts +1790 -0
- package/src/object3DEvent.ts +6 -0
- package/src/orchestrators/RenderPassOrchestrator.ts +147 -0
- package/src/orchestrators/index.ts +1 -0
- package/src/passes/AllDepthCopyPass.ts +165 -0
- package/src/passes/CustomRenderPass.ts +279 -0
- package/src/passes/NormalCopyPass.ts +125 -0
- package/src/passes/RenderTargetCopyPass.ts +91 -0
- package/src/passes/SkyEnvMapPass.ts +58 -0
- package/src/passes/index.ts +5 -0
- package/src/pick/pickHelper.ts +273 -0
- package/src/pick/pickTerrain.ts +254 -0
- package/src/plugins/AttributionPlugin/AttributionPlugin.test.ts +210 -0
- package/src/plugins/AttributionPlugin/attribution.test.ts +225 -0
- package/src/plugins/AttributionPlugin/attribution.ts +355 -0
- package/src/plugins/AttributionPlugin/attributionStyles.ts +163 -0
- package/src/plugins/AttributionPlugin/index.ts +702 -0
- package/src/plugins/index.ts +1 -0
- package/src/quality.ts +1 -0
- package/src/renderOrder.ts +3 -0
- package/src/scene.test.ts +164 -0
- package/src/scene.ts +127 -0
- package/src/shaders/index.ts +1 -0
- package/src/solar.test.ts +81 -0
- package/src/solar.ts +101 -0
- package/src/source.ts +80 -0
- package/src/stats.ts +102 -0
- package/src/tasks/computeVertexNormalsAsync.ts +15 -0
- package/src/tasks/constructPolygonBatchedFeature.ts +34 -0
- package/src/tasks/constructPolylineBatchedFeature.ts +27 -0
- package/src/tasks/constructQuantizedMeshTerrainMesh.ts +24 -0
- package/src/tasks/constructTerrainMesh.ts +25 -0
- package/src/tasks/getImageDataFromBlob.ts +13 -0
- package/src/tasks/getImageDataFromImageBitmap.ts +12 -0
- package/src/tasks/parseMvtTile.ts +22 -0
- package/src/tasks/queueTask.ts +19 -0
- package/src/tasks/toCreasedNormalsAsync.ts +18 -0
- package/src/tasks/upsampleQuantizedMeshTerrainMesh.ts +44 -0
- package/src/tasks/upsampleTerrainMesh.ts +39 -0
- package/src/texture.ts +19 -0
- package/src/textures.ts +13 -0
- package/src/tileTexture/CompositeShader.snapshot.test.ts +59 -0
- package/src/tileTexture/CompositeShader.test.ts +168 -0
- package/src/tileTexture/CompositeShader.ts +53 -0
- package/src/tileTexture/SlotPlanner.test.ts +105 -0
- package/src/tileTexture/SlotPlanner.ts +102 -0
- package/src/tileTexture/TileTextureCache.test.ts +227 -0
- package/src/tileTexture/TileTextureCache.ts +192 -0
- package/src/tileTexture/TileTextureCompositor.test.ts +260 -0
- package/src/tileTexture/TileTextureCompositor.ts +421 -0
- package/src/tileTexture/__snapshots__/CompositeShader.snapshot.test.ts.snap +2649 -0
- package/src/tileTexture/index.ts +8 -0
- package/src/tileTexture/types.ts +150 -0
- package/src/type/index.ts +261 -0
- package/src/uniforms.ts +20 -0
- package/src/utils/arraysEqual.ts +9 -0
- package/src/utils/blendModes.ts +80 -0
- package/src/utils/geometry.ts +53 -0
- package/src/utils/hillshadeNormalMapGenerator.ts +193 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/object.test.ts +14 -0
- package/src/utils/object.ts +7 -0
- package/src/utils/replacer.test.ts +42 -0
- package/src/utils/replacer.ts +89 -0
- package/src/utils/screen.ts +29 -0
- package/src/utils/textureFragmentIndex.test.ts +224 -0
- package/src/utils/textureFragmentIndex.ts +97 -0
- package/src/utils/worker.ts +3 -0
- package/src/vite-env.d.ts +2 -0
- package/src/worker/index.ts +13 -0
- package/src/worker/tasks/computeVertexNormals.ts +15 -0
- package/src/worker/tasks/toCreasedNormals.ts +22 -0
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
import type { EntityEvent, HillshadeBackfilledEvent } from "@navaramap/engine";
|
|
2
|
+
import { Texture } from "three";
|
|
3
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
4
|
+
|
|
5
|
+
import type { EventContext } from "./context";
|
|
6
|
+
import {
|
|
7
|
+
updatePaddingEdge,
|
|
8
|
+
replicateEdgesToPadding,
|
|
9
|
+
processHillshadeBackfilled,
|
|
10
|
+
processHillshadeCanceled,
|
|
11
|
+
} from "./hillshade";
|
|
12
|
+
import { HillshadeContext } from "./HillshadeContext";
|
|
13
|
+
|
|
14
|
+
// Mock generate_id_from_entity
|
|
15
|
+
vi.mock("@navaramap/core", () => ({
|
|
16
|
+
generate_id_from_entity: (event: any) => `${event.ind}_${event.gen}`,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Helper to create a test texture with unique RGBA values per pixel
|
|
21
|
+
* R channel = x coordinate
|
|
22
|
+
* G channel = y coordinate
|
|
23
|
+
* B channel = x + y
|
|
24
|
+
* A channel = 255
|
|
25
|
+
*/
|
|
26
|
+
function createTestTexture(size: number): Uint8Array {
|
|
27
|
+
const buffer = new Uint8Array(size * size * 4);
|
|
28
|
+
for (let y = 0; y < size; y++) {
|
|
29
|
+
for (let x = 0; x < size; x++) {
|
|
30
|
+
const idx = (y * size + x) * 4;
|
|
31
|
+
buffer[idx] = x; // R
|
|
32
|
+
buffer[idx + 1] = y; // G
|
|
33
|
+
buffer[idx + 2] = (x + y) % 256; // B
|
|
34
|
+
buffer[idx + 3] = 255; // A
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return buffer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Helper to get pixel RGBA values from texture
|
|
42
|
+
*/
|
|
43
|
+
function getPixel(
|
|
44
|
+
buffer: Uint8Array,
|
|
45
|
+
x: number,
|
|
46
|
+
y: number,
|
|
47
|
+
width: number,
|
|
48
|
+
): [number, number, number, number] {
|
|
49
|
+
const idx = (y * width + x) * 4;
|
|
50
|
+
return [buffer[idx], buffer[idx + 1], buffer[idx + 2], buffer[idx + 3]];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("replicateEdgesToPadding", () => {
|
|
54
|
+
it("replicates edges for a 4×4 content texture (6×6 padded)", () => {
|
|
55
|
+
const contentSize = 4;
|
|
56
|
+
const paddedSize = contentSize + 2;
|
|
57
|
+
const paddedBytes = new Uint8Array(paddedSize * paddedSize * 4);
|
|
58
|
+
|
|
59
|
+
// Fill center with test pattern
|
|
60
|
+
const testContent = createTestTexture(contentSize);
|
|
61
|
+
for (let y = 0; y < contentSize; y++) {
|
|
62
|
+
for (let x = 0; x < contentSize; x++) {
|
|
63
|
+
const srcIdx = (y * contentSize + x) * 4;
|
|
64
|
+
const dstIdx = ((y + 1) * paddedSize + (x + 1)) * 4;
|
|
65
|
+
paddedBytes[dstIdx] = testContent[srcIdx];
|
|
66
|
+
paddedBytes[dstIdx + 1] = testContent[srcIdx + 1];
|
|
67
|
+
paddedBytes[dstIdx + 2] = testContent[srcIdx + 2];
|
|
68
|
+
paddedBytes[dstIdx + 3] = testContent[srcIdx + 3];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
replicateEdgesToPadding(paddedBytes, paddedSize);
|
|
73
|
+
|
|
74
|
+
// Verify top padding (y=0): should match first content row (y=1)
|
|
75
|
+
for (let x = 1; x <= contentSize; x++) {
|
|
76
|
+
const paddingPixel = getPixel(paddedBytes, x, 0, paddedSize);
|
|
77
|
+
const contentPixel = getPixel(paddedBytes, x, 1, paddedSize);
|
|
78
|
+
expect(paddingPixel).toEqual(contentPixel);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Verify bottom padding (y=5): should match last content row (y=4)
|
|
82
|
+
for (let x = 1; x <= contentSize; x++) {
|
|
83
|
+
const paddingPixel = getPixel(paddedBytes, x, paddedSize - 1, paddedSize);
|
|
84
|
+
const contentPixel = getPixel(paddedBytes, x, contentSize, paddedSize);
|
|
85
|
+
expect(paddingPixel).toEqual(contentPixel);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Verify left padding (x=0): should match first content column (x=1)
|
|
89
|
+
for (let y = 1; y <= contentSize; y++) {
|
|
90
|
+
const paddingPixel = getPixel(paddedBytes, 0, y, paddedSize);
|
|
91
|
+
const contentPixel = getPixel(paddedBytes, 1, y, paddedSize);
|
|
92
|
+
expect(paddingPixel).toEqual(contentPixel);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Verify right padding (x=5): should match last content column (x=4)
|
|
96
|
+
for (let y = 1; y <= contentSize; y++) {
|
|
97
|
+
const paddingPixel = getPixel(paddedBytes, paddedSize - 1, y, paddedSize);
|
|
98
|
+
const contentPixel = getPixel(paddedBytes, contentSize, y, paddedSize);
|
|
99
|
+
expect(paddingPixel).toEqual(contentPixel);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Verify corners
|
|
103
|
+
const topLeft = getPixel(paddedBytes, 0, 0, paddedSize);
|
|
104
|
+
const topLeftContent = getPixel(paddedBytes, 1, 1, paddedSize);
|
|
105
|
+
expect(topLeft).toEqual(topLeftContent);
|
|
106
|
+
|
|
107
|
+
const topRight = getPixel(paddedBytes, paddedSize - 1, 0, paddedSize);
|
|
108
|
+
const topRightContent = getPixel(paddedBytes, contentSize, 1, paddedSize);
|
|
109
|
+
expect(topRight).toEqual(topRightContent);
|
|
110
|
+
|
|
111
|
+
const bottomLeft = getPixel(paddedBytes, 0, paddedSize - 1, paddedSize);
|
|
112
|
+
const bottomLeftContent = getPixel(paddedBytes, 1, contentSize, paddedSize);
|
|
113
|
+
expect(bottomLeft).toEqual(bottomLeftContent);
|
|
114
|
+
|
|
115
|
+
const bottomRight = getPixel(
|
|
116
|
+
paddedBytes,
|
|
117
|
+
paddedSize - 1,
|
|
118
|
+
paddedSize - 1,
|
|
119
|
+
paddedSize,
|
|
120
|
+
);
|
|
121
|
+
const bottomRightContent = getPixel(
|
|
122
|
+
paddedBytes,
|
|
123
|
+
contentSize,
|
|
124
|
+
contentSize,
|
|
125
|
+
paddedSize,
|
|
126
|
+
);
|
|
127
|
+
expect(bottomRight).toEqual(bottomRightContent);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("replicates edges for a 256×256 content texture (258×258 padded)", () => {
|
|
131
|
+
const contentSize = 256;
|
|
132
|
+
const paddedSize = contentSize + 2;
|
|
133
|
+
const paddedBytes = new Uint8Array(paddedSize * paddedSize * 4);
|
|
134
|
+
|
|
135
|
+
// Fill center with test pattern
|
|
136
|
+
const testContent = createTestTexture(contentSize);
|
|
137
|
+
for (let y = 0; y < contentSize; y++) {
|
|
138
|
+
for (let x = 0; x < contentSize; x++) {
|
|
139
|
+
const srcIdx = (y * contentSize + x) * 4;
|
|
140
|
+
const dstIdx = ((y + 1) * paddedSize + (x + 1)) * 4;
|
|
141
|
+
paddedBytes[dstIdx] = testContent[srcIdx];
|
|
142
|
+
paddedBytes[dstIdx + 1] = testContent[srcIdx + 1];
|
|
143
|
+
paddedBytes[dstIdx + 2] = testContent[srcIdx + 2];
|
|
144
|
+
paddedBytes[dstIdx + 3] = testContent[srcIdx + 3];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
replicateEdgesToPadding(paddedBytes, paddedSize);
|
|
149
|
+
|
|
150
|
+
// Sample check: verify a few pixels on each edge
|
|
151
|
+
// Top edge (y=0, x=128) should match (y=1, x=128)
|
|
152
|
+
expect(getPixel(paddedBytes, 128, 0, paddedSize)).toEqual(
|
|
153
|
+
getPixel(paddedBytes, 128, 1, paddedSize),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Bottom edge (y=257, x=128) should match (y=256, x=128)
|
|
157
|
+
expect(getPixel(paddedBytes, 128, 257, paddedSize)).toEqual(
|
|
158
|
+
getPixel(paddedBytes, 128, 256, paddedSize),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Left edge (x=0, y=128) should match (x=1, y=128)
|
|
162
|
+
expect(getPixel(paddedBytes, 0, 128, paddedSize)).toEqual(
|
|
163
|
+
getPixel(paddedBytes, 1, 128, paddedSize),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Right edge (x=257, y=128) should match (x=256, y=128)
|
|
167
|
+
expect(getPixel(paddedBytes, 257, 128, paddedSize)).toEqual(
|
|
168
|
+
getPixel(paddedBytes, 256, 128, paddedSize),
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe("updatePaddingEdge", () => {
|
|
174
|
+
const contentSize = 4;
|
|
175
|
+
const paddedSize = contentSize + 2; // 6×6
|
|
176
|
+
|
|
177
|
+
function createPaddedTexture(): Uint8Array {
|
|
178
|
+
const paddedBytes = new Uint8Array(paddedSize * paddedSize * 4);
|
|
179
|
+
const testContent = createTestTexture(contentSize);
|
|
180
|
+
|
|
181
|
+
// Fill center
|
|
182
|
+
for (let y = 0; y < contentSize; y++) {
|
|
183
|
+
for (let x = 0; x < contentSize; x++) {
|
|
184
|
+
const srcIdx = (y * contentSize + x) * 4;
|
|
185
|
+
const dstIdx = ((y + 1) * paddedSize + (x + 1)) * 4;
|
|
186
|
+
paddedBytes[dstIdx] = testContent[srcIdx];
|
|
187
|
+
paddedBytes[dstIdx + 1] = testContent[srcIdx + 1];
|
|
188
|
+
paddedBytes[dstIdx + 2] = testContent[srcIdx + 2];
|
|
189
|
+
paddedBytes[dstIdx + 3] = testContent[srcIdx + 3];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
replicateEdgesToPadding(paddedBytes, paddedSize);
|
|
194
|
+
return paddedBytes;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function createEdgeData(
|
|
198
|
+
direction: "left" | "right" | "top" | "bottom",
|
|
199
|
+
): Uint8Array {
|
|
200
|
+
const edgeBytes = new Uint8Array(contentSize * 4);
|
|
201
|
+
for (let i = 0; i < contentSize; i++) {
|
|
202
|
+
const idx = i * 4;
|
|
203
|
+
// Use unique values to verify correct placement
|
|
204
|
+
switch (direction) {
|
|
205
|
+
case "left":
|
|
206
|
+
edgeBytes[idx] = 100 + i; // R
|
|
207
|
+
edgeBytes[idx + 1] = i; // G
|
|
208
|
+
break;
|
|
209
|
+
case "right":
|
|
210
|
+
edgeBytes[idx] = 200 + i; // R
|
|
211
|
+
edgeBytes[idx + 1] = i; // G
|
|
212
|
+
break;
|
|
213
|
+
case "top":
|
|
214
|
+
edgeBytes[idx] = i; // R
|
|
215
|
+
edgeBytes[idx + 1] = 100 + i; // G
|
|
216
|
+
break;
|
|
217
|
+
case "bottom":
|
|
218
|
+
edgeBytes[idx] = i; // R
|
|
219
|
+
edgeBytes[idx + 1] = 200 + i; // G
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
edgeBytes[idx + 2] = 50; // B (constant)
|
|
223
|
+
edgeBytes[idx + 3] = 255; // A
|
|
224
|
+
}
|
|
225
|
+
return edgeBytes;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
it("updates left padding (direction=0, x=0)", () => {
|
|
229
|
+
const textureData = createPaddedTexture();
|
|
230
|
+
const edgeBytes = createEdgeData("left");
|
|
231
|
+
|
|
232
|
+
updatePaddingEdge(textureData, edgeBytes, paddedSize, 0);
|
|
233
|
+
|
|
234
|
+
// Verify left padding column (x=0, y=1..4)
|
|
235
|
+
for (let y = 0; y < contentSize; y++) {
|
|
236
|
+
const pixel = getPixel(textureData, 0, y + 1, paddedSize);
|
|
237
|
+
expect(pixel[0]).toBe(100 + y); // R
|
|
238
|
+
expect(pixel[1]).toBe(y); // G
|
|
239
|
+
expect(pixel[2]).toBe(50); // B
|
|
240
|
+
expect(pixel[3]).toBe(255); // A
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("updates right padding (direction=1, x=paddedSize-1)", () => {
|
|
245
|
+
const textureData = createPaddedTexture();
|
|
246
|
+
const edgeBytes = createEdgeData("right");
|
|
247
|
+
|
|
248
|
+
updatePaddingEdge(textureData, edgeBytes, paddedSize, 1);
|
|
249
|
+
|
|
250
|
+
// Verify right padding column (x=5, y=1..4)
|
|
251
|
+
for (let y = 0; y < contentSize; y++) {
|
|
252
|
+
const pixel = getPixel(textureData, paddedSize - 1, y + 1, paddedSize);
|
|
253
|
+
expect(pixel[0]).toBe(200 + y); // R
|
|
254
|
+
expect(pixel[1]).toBe(y); // G
|
|
255
|
+
expect(pixel[2]).toBe(50); // B
|
|
256
|
+
expect(pixel[3]).toBe(255); // A
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("updates top padding (direction=2, y=0)", () => {
|
|
261
|
+
const textureData = createPaddedTexture();
|
|
262
|
+
const edgeBytes = createEdgeData("top");
|
|
263
|
+
|
|
264
|
+
updatePaddingEdge(textureData, edgeBytes, paddedSize, 2);
|
|
265
|
+
|
|
266
|
+
// Verify top padding row (y=0, x=1..4)
|
|
267
|
+
for (let x = 0; x < contentSize; x++) {
|
|
268
|
+
const pixel = getPixel(textureData, x + 1, 0, paddedSize);
|
|
269
|
+
expect(pixel[0]).toBe(x); // R
|
|
270
|
+
expect(pixel[1]).toBe(100 + x); // G
|
|
271
|
+
expect(pixel[2]).toBe(50); // B
|
|
272
|
+
expect(pixel[3]).toBe(255); // A
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("updates bottom padding (direction=3, y=paddedSize-1)", () => {
|
|
277
|
+
const textureData = createPaddedTexture();
|
|
278
|
+
const edgeBytes = createEdgeData("bottom");
|
|
279
|
+
|
|
280
|
+
updatePaddingEdge(textureData, edgeBytes, paddedSize, 3);
|
|
281
|
+
|
|
282
|
+
// Verify bottom padding row (y=5, x=1..4)
|
|
283
|
+
for (let x = 0; x < contentSize; x++) {
|
|
284
|
+
const pixel = getPixel(textureData, x + 1, paddedSize - 1, paddedSize);
|
|
285
|
+
expect(pixel[0]).toBe(x); // R
|
|
286
|
+
expect(pixel[1]).toBe(200 + x); // G
|
|
287
|
+
expect(pixel[2]).toBe(50); // B
|
|
288
|
+
expect(pixel[3]).toBe(255); // A
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("does not modify content area when updating padding", () => {
|
|
293
|
+
const textureData = createPaddedTexture();
|
|
294
|
+
const edgeBytes = createEdgeData("left");
|
|
295
|
+
|
|
296
|
+
// Capture content before update
|
|
297
|
+
const contentBefore = new Uint8Array(contentSize * contentSize * 4);
|
|
298
|
+
for (let y = 0; y < contentSize; y++) {
|
|
299
|
+
for (let x = 0; x < contentSize; x++) {
|
|
300
|
+
const srcIdx = ((y + 1) * paddedSize + (x + 1)) * 4;
|
|
301
|
+
const dstIdx = (y * contentSize + x) * 4;
|
|
302
|
+
contentBefore[dstIdx] = textureData[srcIdx];
|
|
303
|
+
contentBefore[dstIdx + 1] = textureData[srcIdx + 1];
|
|
304
|
+
contentBefore[dstIdx + 2] = textureData[srcIdx + 2];
|
|
305
|
+
contentBefore[dstIdx + 3] = textureData[srcIdx + 3];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
updatePaddingEdge(textureData, edgeBytes, paddedSize, 0);
|
|
310
|
+
|
|
311
|
+
// Verify content is unchanged
|
|
312
|
+
for (let y = 0; y < contentSize; y++) {
|
|
313
|
+
for (let x = 0; x < contentSize; x++) {
|
|
314
|
+
const srcIdx = ((y + 1) * paddedSize + (x + 1)) * 4;
|
|
315
|
+
const dstIdx = (y * contentSize + x) * 4;
|
|
316
|
+
expect(textureData[srcIdx]).toBe(contentBefore[dstIdx]);
|
|
317
|
+
expect(textureData[srcIdx + 1]).toBe(contentBefore[dstIdx + 1]);
|
|
318
|
+
expect(textureData[srcIdx + 2]).toBe(contentBefore[dstIdx + 2]);
|
|
319
|
+
expect(textureData[srcIdx + 3]).toBe(contentBefore[dstIdx + 3]);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("handles 256×256 content (258×258 padded)", () => {
|
|
325
|
+
const largeContentSize = 256;
|
|
326
|
+
const largePaddedSize = largeContentSize + 2;
|
|
327
|
+
const textureData = new Uint8Array(largePaddedSize * largePaddedSize * 4);
|
|
328
|
+
const edgeBytes = new Uint8Array(largeContentSize * 4);
|
|
329
|
+
|
|
330
|
+
// Fill edge with marker values
|
|
331
|
+
for (let i = 0; i < largeContentSize; i++) {
|
|
332
|
+
edgeBytes[i * 4] = 123; // R
|
|
333
|
+
edgeBytes[i * 4 + 1] = i % 256; // G
|
|
334
|
+
edgeBytes[i * 4 + 2] = 45; // B
|
|
335
|
+
edgeBytes[i * 4 + 3] = 255; // A
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
updatePaddingEdge(textureData, edgeBytes, largePaddedSize, 0);
|
|
339
|
+
|
|
340
|
+
// Verify left padding (sample a few pixels)
|
|
341
|
+
for (let y = 0; y < largeContentSize; y += 64) {
|
|
342
|
+
const pixel = getPixel(textureData, 0, y + 1, largePaddedSize);
|
|
343
|
+
expect(pixel[0]).toBe(123);
|
|
344
|
+
expect(pixel[1]).toBe(y % 256);
|
|
345
|
+
expect(pixel[2]).toBe(45);
|
|
346
|
+
expect(pixel[3]).toBe(255);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Tests for hillshade normal map generation lifecycle
|
|
353
|
+
* Covers: original-before-edges, edges-before-original, size mismatch, temp DEM cleanup
|
|
354
|
+
*/
|
|
355
|
+
describe("hillshade normal map generation", () => {
|
|
356
|
+
let mockContext: EventContext;
|
|
357
|
+
let hillshadeContext: HillshadeContext;
|
|
358
|
+
let loadedTexs: Map<string, Texture>;
|
|
359
|
+
let mockBufferStore: Map<number, Uint8Array>;
|
|
360
|
+
let nextHandle: number;
|
|
361
|
+
|
|
362
|
+
beforeEach(() => {
|
|
363
|
+
// Reset state for each test
|
|
364
|
+
hillshadeContext = new HillshadeContext();
|
|
365
|
+
loadedTexs = new Map();
|
|
366
|
+
mockBufferStore = new Map();
|
|
367
|
+
nextHandle = 1;
|
|
368
|
+
|
|
369
|
+
// Create mock ViewContext with renderer
|
|
370
|
+
const mockRenderer = {
|
|
371
|
+
getRenderTarget: vi.fn(() => null),
|
|
372
|
+
setRenderTarget: vi.fn(),
|
|
373
|
+
render: vi.fn(),
|
|
374
|
+
readRenderTargetPixels: vi.fn((_target, _x, _y, _w, _h, buffer) => {
|
|
375
|
+
// Fill with test pattern
|
|
376
|
+
for (let i = 0; i < buffer.length; i += 4) {
|
|
377
|
+
buffer[i] = 128; // R
|
|
378
|
+
buffer[i + 1] = 128; // G
|
|
379
|
+
buffer[i + 2] = 255; // B
|
|
380
|
+
buffer[i + 3] = 255; // A
|
|
381
|
+
}
|
|
382
|
+
}),
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const mockViewContext = {
|
|
386
|
+
getRenderer: () => mockRenderer,
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Create mock TileHandler
|
|
390
|
+
const mockTileHandler = {
|
|
391
|
+
getTile: vi.fn((_handle: bigint) => ({
|
|
392
|
+
coords: { z: 14, x: 14507, y: 6473 },
|
|
393
|
+
})),
|
|
394
|
+
calcMetersPerTexel: vi.fn(() => 7.798810005187988),
|
|
395
|
+
getTileElevationDecoder: vi.fn(() => ({
|
|
396
|
+
r_scaler: 256,
|
|
397
|
+
g_scaler: 1,
|
|
398
|
+
b_scaler: 1 / 256,
|
|
399
|
+
boundary: 0,
|
|
400
|
+
min_offset: 0,
|
|
401
|
+
max_offset: 0,
|
|
402
|
+
epsilon: 1.0,
|
|
403
|
+
offset: -32768,
|
|
404
|
+
})),
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// Create mock BufferStore
|
|
408
|
+
const mockBuf = {
|
|
409
|
+
u8: vi.fn((handle: number) => mockBufferStore.get(handle)),
|
|
410
|
+
removeU8: vi.fn((handle: number) => mockBufferStore.get(handle)),
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// Create mock texture fragment index
|
|
414
|
+
const mockTextureFragmentIndex = new Map();
|
|
415
|
+
|
|
416
|
+
// Create mock texture options
|
|
417
|
+
const mockTextureOptions = new Map();
|
|
418
|
+
|
|
419
|
+
mockContext = {
|
|
420
|
+
viewContext: mockViewContext as any,
|
|
421
|
+
loadedTexs,
|
|
422
|
+
buf: mockBuf as any,
|
|
423
|
+
textureFragmentIndex: mockTextureFragmentIndex as any,
|
|
424
|
+
textureOptions: mockTextureOptions as any,
|
|
425
|
+
tileHandler: mockTileHandler as any,
|
|
426
|
+
hillshadeContext,
|
|
427
|
+
eventManager: {
|
|
428
|
+
stacks: { hillshade_backfilled: [] },
|
|
429
|
+
},
|
|
430
|
+
} as unknown as EventContext;
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Helper to create test DEM data (4×4 content = 16 pixels)
|
|
435
|
+
*/
|
|
436
|
+
function createTestDemData(): Uint8Array {
|
|
437
|
+
const size = 4;
|
|
438
|
+
const buffer = new Uint8Array(size * size * 4);
|
|
439
|
+
for (let y = 0; y < size; y++) {
|
|
440
|
+
for (let x = 0; x < size; x++) {
|
|
441
|
+
const idx = (y * size + x) * 4;
|
|
442
|
+
buffer[idx] = x * 10; // R
|
|
443
|
+
buffer[idx + 1] = y * 10; // G
|
|
444
|
+
buffer[idx + 2] = (x + y) * 5; // B
|
|
445
|
+
buffer[idx + 3] = 255; // A
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return buffer;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Helper to create edge data (4 pixels for a 4×4 content texture)
|
|
453
|
+
*/
|
|
454
|
+
function createEdgeData(value: number): Uint8Array {
|
|
455
|
+
const edgeSize = 4;
|
|
456
|
+
const buffer = new Uint8Array(edgeSize * 4);
|
|
457
|
+
for (let i = 0; i < edgeSize; i++) {
|
|
458
|
+
buffer[i * 4] = value; // R
|
|
459
|
+
buffer[i * 4 + 1] = value + 10; // G
|
|
460
|
+
buffer[i * 4 + 2] = value + 20; // B
|
|
461
|
+
buffer[i * 4 + 3] = 255; // A
|
|
462
|
+
}
|
|
463
|
+
return buffer;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Helper to store buffer and get handle
|
|
468
|
+
*/
|
|
469
|
+
function storeBuffer(data: Uint8Array): number {
|
|
470
|
+
const handle = nextHandle++;
|
|
471
|
+
mockBufferStore.set(handle, data);
|
|
472
|
+
return handle;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
it("generates normal map when original DEM arrives (original-before-edges)", () => {
|
|
476
|
+
const entityId = "1_123"; // Format: {entity_ind}_{entity_gen}
|
|
477
|
+
const demData = createTestDemData();
|
|
478
|
+
const demHandle = storeBuffer(demData);
|
|
479
|
+
|
|
480
|
+
const event = {
|
|
481
|
+
ind: 1,
|
|
482
|
+
gen: 123,
|
|
483
|
+
tile_handle: 999n,
|
|
484
|
+
original_handle: demHandle,
|
|
485
|
+
edge_data_handle: -1,
|
|
486
|
+
edge_direction: 0,
|
|
487
|
+
target_entity_ind: undefined,
|
|
488
|
+
target_entity_gen: undefined,
|
|
489
|
+
} as HillshadeBackfilledEvent;
|
|
490
|
+
|
|
491
|
+
processHillshadeBackfilled(mockContext, event);
|
|
492
|
+
|
|
493
|
+
// Verify normal map was generated and stored
|
|
494
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
495
|
+
const normalMap = loadedTexs.get(entityId);
|
|
496
|
+
expect(normalMap).toBeInstanceOf(Texture);
|
|
497
|
+
if (normalMap) {
|
|
498
|
+
expect((normalMap.image as { width: number }).width).toBe(4); // Content size (no padding in normal map)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Verify temp DEM entry was stored for edge updates
|
|
502
|
+
const tempDem = hillshadeContext.getTempDem(entityId);
|
|
503
|
+
expect(tempDem).toBeDefined();
|
|
504
|
+
expect(tempDem?.originalHandle).toBe(demHandle);
|
|
505
|
+
expect(tempDem?.paddedSize).toBe(6); // Padded size (4 + 2)
|
|
506
|
+
expect(tempDem?.receivedEdges.size).toBe(0);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it("regenerates normal map when edge arrives after original", () => {
|
|
510
|
+
const entityId = "1_123"; // Format: {entity_ind}_{entity_gen}
|
|
511
|
+
|
|
512
|
+
// Step 1: Original DEM arrives
|
|
513
|
+
const demData = createTestDemData();
|
|
514
|
+
const demHandle = storeBuffer(demData);
|
|
515
|
+
processHillshadeBackfilled(mockContext, {
|
|
516
|
+
ind: 1,
|
|
517
|
+
gen: 123,
|
|
518
|
+
tile_handle: 999n,
|
|
519
|
+
original_handle: demHandle,
|
|
520
|
+
edge_data_handle: -1,
|
|
521
|
+
edge_direction: 0,
|
|
522
|
+
target_entity_ind: undefined,
|
|
523
|
+
target_entity_gen: undefined,
|
|
524
|
+
} as HillshadeBackfilledEvent);
|
|
525
|
+
|
|
526
|
+
const firstNormalMap = loadedTexs.get(entityId);
|
|
527
|
+
expect(firstNormalMap).toBeInstanceOf(Texture);
|
|
528
|
+
|
|
529
|
+
// Step 2: Left edge arrives (direction 0)
|
|
530
|
+
const edgeData = createEdgeData(100);
|
|
531
|
+
const edgeHandle = storeBuffer(edgeData);
|
|
532
|
+
processHillshadeBackfilled(mockContext, {
|
|
533
|
+
ind: 999,
|
|
534
|
+
gen: 999,
|
|
535
|
+
tile_handle: 999n,
|
|
536
|
+
original_handle: -1,
|
|
537
|
+
edge_data_handle: edgeHandle,
|
|
538
|
+
edge_direction: 0,
|
|
539
|
+
target_entity_ind: 1,
|
|
540
|
+
target_entity_gen: 123,
|
|
541
|
+
} as HillshadeBackfilledEvent);
|
|
542
|
+
|
|
543
|
+
// Verify normal map is still the same texture instance (RenderTarget reuse)
|
|
544
|
+
// Content is updated in-place on GPU, texture reference stays the same
|
|
545
|
+
const secondNormalMap = loadedTexs.get(entityId);
|
|
546
|
+
expect(secondNormalMap).toBeInstanceOf(Texture);
|
|
547
|
+
expect(secondNormalMap).toBe(firstNormalMap); // Same texture instance (updated in-place)
|
|
548
|
+
|
|
549
|
+
// Verify edge was marked as received
|
|
550
|
+
const tempDem = hillshadeContext.getTempDem(entityId);
|
|
551
|
+
expect(tempDem?.receivedEdges.has(0)).toBe(true);
|
|
552
|
+
expect(tempDem?.receivedEdges.size).toBe(1);
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it("cleans up temp DEM after all 4 edges received", () => {
|
|
556
|
+
const entityId = "1_123"; // Format: {entity_ind}_{entity_gen}
|
|
557
|
+
|
|
558
|
+
// Step 1: Original arrives
|
|
559
|
+
const demData = createTestDemData();
|
|
560
|
+
processHillshadeBackfilled(mockContext, {
|
|
561
|
+
ind: 1,
|
|
562
|
+
gen: 123,
|
|
563
|
+
tile_handle: 999n,
|
|
564
|
+
original_handle: storeBuffer(demData),
|
|
565
|
+
edge_data_handle: -1,
|
|
566
|
+
edge_direction: 0,
|
|
567
|
+
target_entity_ind: undefined,
|
|
568
|
+
target_entity_gen: undefined,
|
|
569
|
+
} as HillshadeBackfilledEvent);
|
|
570
|
+
|
|
571
|
+
expect(hillshadeContext.getTempDem(entityId)).toBeDefined();
|
|
572
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
573
|
+
|
|
574
|
+
// Step 2-5: All 4 edges arrive (directions 0, 1, 2, 3)
|
|
575
|
+
for (let direction = 0; direction < 4; direction++) {
|
|
576
|
+
processHillshadeBackfilled(mockContext, {
|
|
577
|
+
ind: 999,
|
|
578
|
+
gen: 999,
|
|
579
|
+
tile_handle: 999n,
|
|
580
|
+
original_handle: -1,
|
|
581
|
+
edge_data_handle: storeBuffer(createEdgeData(100 + direction)),
|
|
582
|
+
edge_direction: direction,
|
|
583
|
+
target_entity_ind: 1,
|
|
584
|
+
target_entity_gen: 123,
|
|
585
|
+
} as HillshadeBackfilledEvent);
|
|
586
|
+
|
|
587
|
+
if (direction < 3) {
|
|
588
|
+
// Not all edges received yet
|
|
589
|
+
expect(hillshadeContext.getTempDem(entityId)).toBeDefined();
|
|
590
|
+
expect(hillshadeContext.getTempDem(entityId)?.receivedEdges.size).toBe(
|
|
591
|
+
direction + 1,
|
|
592
|
+
);
|
|
593
|
+
} else {
|
|
594
|
+
// All 4 edges received, temp DEM should be cleaned up
|
|
595
|
+
expect(hillshadeContext.getTempDem(entityId)).toBeUndefined();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Verify texture still exists after cleanup
|
|
600
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
it("queues edges that arrive before original (edges-before-original)", () => {
|
|
604
|
+
const entityId = "1_123"; // Format: {entity_ind}_{entity_gen}
|
|
605
|
+
|
|
606
|
+
// Step 1: Edges arrive first (directions 0, 1)
|
|
607
|
+
processHillshadeBackfilled(mockContext, {
|
|
608
|
+
ind: 999,
|
|
609
|
+
gen: 999,
|
|
610
|
+
tile_handle: 999n,
|
|
611
|
+
original_handle: -1,
|
|
612
|
+
edge_data_handle: storeBuffer(createEdgeData(100)),
|
|
613
|
+
edge_direction: 0,
|
|
614
|
+
target_entity_ind: 1,
|
|
615
|
+
target_entity_gen: 123,
|
|
616
|
+
} as HillshadeBackfilledEvent);
|
|
617
|
+
|
|
618
|
+
processHillshadeBackfilled(mockContext, {
|
|
619
|
+
ind: 999,
|
|
620
|
+
gen: 999,
|
|
621
|
+
tile_handle: 999n,
|
|
622
|
+
original_handle: -1,
|
|
623
|
+
edge_data_handle: storeBuffer(createEdgeData(110)),
|
|
624
|
+
edge_direction: 1,
|
|
625
|
+
target_entity_ind: 1,
|
|
626
|
+
target_entity_gen: 123,
|
|
627
|
+
} as HillshadeBackfilledEvent);
|
|
628
|
+
|
|
629
|
+
// Verify edges are queued, no texture created yet
|
|
630
|
+
expect(loadedTexs.has(entityId)).toBe(false);
|
|
631
|
+
const pendingMap = hillshadeContext.pendingEdges.get(entityId);
|
|
632
|
+
expect(pendingMap).toBeDefined();
|
|
633
|
+
expect(pendingMap?.size).toBe(2);
|
|
634
|
+
expect(pendingMap?.has(0)).toBe(true);
|
|
635
|
+
expect(pendingMap?.has(1)).toBe(true);
|
|
636
|
+
|
|
637
|
+
// Step 2: Original arrives
|
|
638
|
+
const demData = createTestDemData();
|
|
639
|
+
processHillshadeBackfilled(mockContext, {
|
|
640
|
+
ind: 1,
|
|
641
|
+
gen: 123,
|
|
642
|
+
tile_handle: 999n,
|
|
643
|
+
original_handle: storeBuffer(demData),
|
|
644
|
+
edge_data_handle: -1,
|
|
645
|
+
edge_direction: 0,
|
|
646
|
+
target_entity_ind: undefined,
|
|
647
|
+
target_entity_gen: undefined,
|
|
648
|
+
} as HillshadeBackfilledEvent);
|
|
649
|
+
|
|
650
|
+
// Verify normal map was generated with pending edges applied
|
|
651
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
652
|
+
expect(loadedTexs.get(entityId)).toBeInstanceOf(Texture);
|
|
653
|
+
|
|
654
|
+
// Verify pending edges were cleared
|
|
655
|
+
expect(hillshadeContext.pendingEdges.has(entityId)).toBe(false);
|
|
656
|
+
|
|
657
|
+
// Verify edges were marked as received in temp DEM
|
|
658
|
+
const tempDem = hillshadeContext.getTempDem(entityId);
|
|
659
|
+
expect(tempDem?.receivedEdges.has(0)).toBe(true);
|
|
660
|
+
expect(tempDem?.receivedEdges.has(1)).toBe(true);
|
|
661
|
+
expect(tempDem?.receivedEdges.size).toBe(2);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it("handles multiple entities independently", () => {
|
|
665
|
+
const entity1 = "1_123";
|
|
666
|
+
const entity2 = "2_456";
|
|
667
|
+
|
|
668
|
+
// Create textures for both entities
|
|
669
|
+
processHillshadeBackfilled(mockContext, {
|
|
670
|
+
ind: 1,
|
|
671
|
+
gen: 123,
|
|
672
|
+
tile_handle: 999n,
|
|
673
|
+
original_handle: storeBuffer(createTestDemData()),
|
|
674
|
+
edge_data_handle: -1,
|
|
675
|
+
edge_direction: 0,
|
|
676
|
+
target_entity_ind: undefined,
|
|
677
|
+
target_entity_gen: undefined,
|
|
678
|
+
} as HillshadeBackfilledEvent);
|
|
679
|
+
|
|
680
|
+
processHillshadeBackfilled(mockContext, {
|
|
681
|
+
ind: 2,
|
|
682
|
+
gen: 456,
|
|
683
|
+
tile_handle: 888n,
|
|
684
|
+
original_handle: storeBuffer(createTestDemData()),
|
|
685
|
+
edge_data_handle: -1,
|
|
686
|
+
edge_direction: 0,
|
|
687
|
+
target_entity_ind: undefined,
|
|
688
|
+
target_entity_gen: undefined,
|
|
689
|
+
} as HillshadeBackfilledEvent);
|
|
690
|
+
|
|
691
|
+
// Verify both have textures and temp DEMs
|
|
692
|
+
expect(loadedTexs.has(entity1)).toBe(true);
|
|
693
|
+
expect(loadedTexs.has(entity2)).toBe(true);
|
|
694
|
+
expect(hillshadeContext.getTempDem(entity1)).toBeDefined();
|
|
695
|
+
expect(hillshadeContext.getTempDem(entity2)).toBeDefined();
|
|
696
|
+
|
|
697
|
+
// Send edge to entity1
|
|
698
|
+
processHillshadeBackfilled(mockContext, {
|
|
699
|
+
ind: 999,
|
|
700
|
+
gen: 999,
|
|
701
|
+
tile_handle: 999n,
|
|
702
|
+
original_handle: -1,
|
|
703
|
+
edge_data_handle: storeBuffer(createEdgeData(100)),
|
|
704
|
+
edge_direction: 0,
|
|
705
|
+
target_entity_ind: 1,
|
|
706
|
+
target_entity_gen: 123,
|
|
707
|
+
} as HillshadeBackfilledEvent);
|
|
708
|
+
|
|
709
|
+
// Verify only entity1 was updated
|
|
710
|
+
const tempDem1 = hillshadeContext.getTempDem(entity1);
|
|
711
|
+
const tempDem2 = hillshadeContext.getTempDem(entity2);
|
|
712
|
+
expect(tempDem1?.receivedEdges.size).toBe(1);
|
|
713
|
+
expect(tempDem2?.receivedEdges.size).toBe(0);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it("clears pendingEdges and tempDem on cancel but leaves loadedTexs alone", () => {
|
|
717
|
+
const entityId = "1_123";
|
|
718
|
+
|
|
719
|
+
// Queue a pending edge before any texture exists
|
|
720
|
+
processHillshadeBackfilled(mockContext, {
|
|
721
|
+
ind: 999,
|
|
722
|
+
gen: 999,
|
|
723
|
+
tile_handle: 999n,
|
|
724
|
+
original_handle: -1,
|
|
725
|
+
edge_data_handle: storeBuffer(createEdgeData(100)),
|
|
726
|
+
edge_direction: 0,
|
|
727
|
+
target_entity_ind: 1,
|
|
728
|
+
target_entity_gen: 123,
|
|
729
|
+
} as HillshadeBackfilledEvent);
|
|
730
|
+
expect(hillshadeContext.pendingEdges.get(entityId)?.size).toBe(1);
|
|
731
|
+
|
|
732
|
+
// Also seed loadedTexs / tempDem via initial backfill
|
|
733
|
+
processHillshadeBackfilled(mockContext, {
|
|
734
|
+
ind: 1,
|
|
735
|
+
gen: 123,
|
|
736
|
+
tile_handle: 999n,
|
|
737
|
+
original_handle: storeBuffer(createTestDemData()),
|
|
738
|
+
edge_data_handle: -1,
|
|
739
|
+
edge_direction: 255,
|
|
740
|
+
target_entity_ind: undefined,
|
|
741
|
+
target_entity_gen: undefined,
|
|
742
|
+
} as HillshadeBackfilledEvent);
|
|
743
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
744
|
+
|
|
745
|
+
// Cancel the entity
|
|
746
|
+
processHillshadeCanceled(mockContext, {
|
|
747
|
+
ind: 1,
|
|
748
|
+
gen: 123,
|
|
749
|
+
} as EntityEvent);
|
|
750
|
+
|
|
751
|
+
// In-flight state should be dropped
|
|
752
|
+
expect(hillshadeContext.pendingEdges.has(entityId)).toBe(false);
|
|
753
|
+
expect(hillshadeContext.getTempDem(entityId)).toBeUndefined();
|
|
754
|
+
// Texture lifecycle belongs to texture_fragment_removed, not cancel
|
|
755
|
+
expect(loadedTexs.has(entityId)).toBe(true);
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
it("is idempotent for entities with no hillshade state", () => {
|
|
759
|
+
// Cancel an entity that was never seen — must not throw or create state
|
|
760
|
+
expect(() =>
|
|
761
|
+
processHillshadeCanceled(mockContext, {
|
|
762
|
+
ind: 42,
|
|
763
|
+
gen: 7,
|
|
764
|
+
} as EntityEvent),
|
|
765
|
+
).not.toThrow();
|
|
766
|
+
expect(hillshadeContext.pendingEdges.size).toBe(0);
|
|
767
|
+
expect(loadedTexs.size).toBe(0);
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("drops pending backfills targeting the canceled entity but keeps others", () => {
|
|
771
|
+
// Source X has init + 2 edge updates queued. A neighbor Z also has an init
|
|
772
|
+
// queued. Canceling X should drop X's init only; X→Y edge update (keyed by
|
|
773
|
+
// target Y) and Z's init must survive.
|
|
774
|
+
const initX = {
|
|
775
|
+
ind: 10,
|
|
776
|
+
gen: 1,
|
|
777
|
+
tile_handle: 1n,
|
|
778
|
+
original_handle: 42,
|
|
779
|
+
edge_data_handle: -1,
|
|
780
|
+
edge_direction: 255,
|
|
781
|
+
target_entity_ind: undefined,
|
|
782
|
+
target_entity_gen: undefined,
|
|
783
|
+
free: vi.fn(),
|
|
784
|
+
} as unknown as HillshadeBackfilledEvent;
|
|
785
|
+
const edgeXtoY = {
|
|
786
|
+
ind: 10,
|
|
787
|
+
gen: 1,
|
|
788
|
+
tile_handle: 1n,
|
|
789
|
+
original_handle: -1,
|
|
790
|
+
edge_data_handle: 100,
|
|
791
|
+
edge_direction: 0,
|
|
792
|
+
target_entity_ind: 20,
|
|
793
|
+
target_entity_gen: 1,
|
|
794
|
+
free: vi.fn(),
|
|
795
|
+
} as unknown as HillshadeBackfilledEvent;
|
|
796
|
+
const edgeXtoX = {
|
|
797
|
+
ind: 10,
|
|
798
|
+
gen: 1,
|
|
799
|
+
tile_handle: 1n,
|
|
800
|
+
original_handle: -1,
|
|
801
|
+
edge_data_handle: 101,
|
|
802
|
+
edge_direction: 1,
|
|
803
|
+
target_entity_ind: 10,
|
|
804
|
+
target_entity_gen: 1,
|
|
805
|
+
free: vi.fn(),
|
|
806
|
+
} as unknown as HillshadeBackfilledEvent;
|
|
807
|
+
const initZ = {
|
|
808
|
+
ind: 30,
|
|
809
|
+
gen: 2,
|
|
810
|
+
tile_handle: 2n,
|
|
811
|
+
original_handle: 43,
|
|
812
|
+
edge_data_handle: -1,
|
|
813
|
+
edge_direction: 255,
|
|
814
|
+
target_entity_ind: undefined,
|
|
815
|
+
target_entity_gen: undefined,
|
|
816
|
+
free: vi.fn(),
|
|
817
|
+
} as unknown as HillshadeBackfilledEvent;
|
|
818
|
+
|
|
819
|
+
const stack: HillshadeBackfilledEvent[] = [
|
|
820
|
+
initX,
|
|
821
|
+
edgeXtoY,
|
|
822
|
+
edgeXtoX,
|
|
823
|
+
initZ,
|
|
824
|
+
];
|
|
825
|
+
(mockContext.eventManager as any).stacks.hillshade_backfilled = stack;
|
|
826
|
+
|
|
827
|
+
processHillshadeCanceled(mockContext, {
|
|
828
|
+
ind: 10,
|
|
829
|
+
gen: 1,
|
|
830
|
+
} as EntityEvent);
|
|
831
|
+
|
|
832
|
+
// initX (id "10_1") and edgeXtoX (target "10_1") are dropped.
|
|
833
|
+
// edgeXtoY (target "20_1") and initZ (id "30_2") survive.
|
|
834
|
+
expect(
|
|
835
|
+
(mockContext.eventManager as any).stacks.hillshade_backfilled,
|
|
836
|
+
).toEqual([edgeXtoY, initZ]);
|
|
837
|
+
expect(initX.free).toHaveBeenCalledTimes(1);
|
|
838
|
+
expect(edgeXtoX.free).toHaveBeenCalledTimes(1);
|
|
839
|
+
expect(edgeXtoY.free).not.toHaveBeenCalled();
|
|
840
|
+
expect(initZ.free).not.toHaveBeenCalled();
|
|
841
|
+
});
|
|
842
|
+
});
|