@woosh/meep-engine 3.64.1 → 3.65.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/CHANGELOG.md +85 -0
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts +5 -0
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +39 -5
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +65 -6
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +451 -101
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +4 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +4 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +8 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +45 -10
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +237 -119
- package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts +143 -0
- package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GrassSpecies.js +189 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.d.ts +25 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.js +32 -0
- package/src/engine/graphics/ecs/grass/GroundCover.d.ts +68 -0
- package/src/engine/graphics/ecs/grass/GroundCover.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GroundCover.js +85 -0
- package/src/engine/graphics3/GrassSurfaceSystem.d.ts +153 -0
- package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
- package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
- package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
- package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
- package/src/engine/graphics3/GroundCoverSystem.js +58 -0
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +372 -110
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
- package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +65 -9
- package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
- package/src/engine/network/state/PredictionHistory.js +6 -1
- package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
- package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
- package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
- package/src/engine/network/time/RenderPlayout.d.ts +23 -3
- package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
- package/src/engine/network/time/RenderPlayout.js +40 -4
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
- package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
- package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
- package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
- package/src/shade/playground/grass_surfaces/index.html +75 -0
- package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
- package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
- package/src/shade/playground/grass_surfaces/main.js +593 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
- package/src/shade/playground/probe_clipmap_box/README.md +5 -1
- package/src/shade/playground/probe_clipmap_box/index.html +12 -0
- package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap_box/main.js +15 -0
- package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
- package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +47 -43
- package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
- package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
- package/src/shade/renderer/extension/ViewTextures.js +19 -5
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +3 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
- package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
- package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
|
@@ -0,0 +1,1076 @@
|
|
|
1
|
+
import { assert } from "../../core/assert.js";
|
|
2
|
+
import { m4_from_rotation_translation_scale_array } from "../../core/geom/3d/mat4/m4_from_rotation_translation_scale_array.js";
|
|
3
|
+
import { FramePhase } from "../../shade/renderer/extension/FramePhase.js";
|
|
4
|
+
import { RenderExtension } from "../../shade/renderer/extension/RenderExtension.js";
|
|
5
|
+
import { GPUGrassBlades } from "../../shade/renderer/grass/blade/GPUGrassBlades.js";
|
|
6
|
+
import { GPUGrassSurfaces } from "../../shade/renderer/grass/surface/GPUGrassSurfaces.js";
|
|
7
|
+
import { grass_surface_lattice_bits } from "../../shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js";
|
|
8
|
+
import {
|
|
9
|
+
MESH_GROUND_COVER_FLAG_GROWS,
|
|
10
|
+
MESH_GROUND_COVER_FLAG_MEMBER
|
|
11
|
+
} from "../../shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js";
|
|
12
|
+
import { row_of_entity } from "../../shade/renderer/scene/rows/GPUSceneRows.js";
|
|
13
|
+
import { EventType } from "../ecs/EventType.js";
|
|
14
|
+
import { System } from "../ecs/System.js";
|
|
15
|
+
import { TRANSFORM_ATTACHMENT_EVENT_CHANGE } from "../ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js";
|
|
16
|
+
import { TransformAttachment } from "../ecs/transform-attachment/TransformAttachment.js";
|
|
17
|
+
import { TRANSFORM64_EVENT_CHANGE } from "../ecs/transform/TRANSFORM64_EVENT_CHANGE.js";
|
|
18
|
+
import {
|
|
19
|
+
Transform64,
|
|
20
|
+
TRANSFORM64_ROTATION_OFFSET,
|
|
21
|
+
TRANSFORM64_SCALE_OFFSET,
|
|
22
|
+
TRANSFORM64_TRANSLATION_OFFSET
|
|
23
|
+
} from "../ecs/transform/Transform64.js";
|
|
24
|
+
import { GrassSurface } from "../graphics/ecs/grass/GrassSurface.js";
|
|
25
|
+
import { GPUFluidSystem } from "./GPUFluidSystem.js";
|
|
26
|
+
import { SHADED_GEOMETRY_EVENT_CHANGE } from "../graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.js";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {import("../../shade/renderer/scene/GPUSceneContext.js").GPUSceneContext} GPUSceneContext
|
|
30
|
+
* @typedef {import("../../shade/renderer/scene/Scene.js").Scene} Scene
|
|
31
|
+
* @typedef {import("../graphics/ecs/grass/GrassSpecies.js").GrassSpecies} GrassSpecies
|
|
32
|
+
* @typedef {import("../graphics/ecs/grass/GroundCover.js").GroundCover} GroundCover
|
|
33
|
+
* @typedef {import("../graphics/ecs/mesh-v2/ShadedGeometry.js").ShadedGeometry} ShadedGeometry
|
|
34
|
+
* @typedef {import("./GraphicsEngine.js").GraphicsEngine} GraphicsEngine
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A grass surface's entity, and what is held on its behalf.
|
|
39
|
+
*/
|
|
40
|
+
class SurfaceEntry {
|
|
41
|
+
/** @type {number} */
|
|
42
|
+
entity = -1;
|
|
43
|
+
|
|
44
|
+
/** @type {Transform64} */
|
|
45
|
+
transform = null;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Whether the entity's `transforms` row is held in the current context.
|
|
49
|
+
* @type {boolean}
|
|
50
|
+
*/
|
|
51
|
+
held = false;
|
|
52
|
+
|
|
53
|
+
/** @type {function(): void} */
|
|
54
|
+
on_world = null;
|
|
55
|
+
|
|
56
|
+
/** @type {function(): void} */
|
|
57
|
+
on_local = null;
|
|
58
|
+
|
|
59
|
+
/** @type {function({klass: Function}): void} */
|
|
60
|
+
on_components = null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A mesh entity that is ground of a surface.
|
|
65
|
+
*/
|
|
66
|
+
class MemberEntry {
|
|
67
|
+
/** @type {number} */
|
|
68
|
+
entity = -1;
|
|
69
|
+
|
|
70
|
+
/** @type {GroundCover} */
|
|
71
|
+
cover = null;
|
|
72
|
+
|
|
73
|
+
/** @type {ShadedGeometry} */
|
|
74
|
+
shaded = null;
|
|
75
|
+
|
|
76
|
+
/** @type {Transform64} */
|
|
77
|
+
transform = null;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The species the entry is counted under, which is the cover's as of the last write.
|
|
81
|
+
* @type {GrassSpecies|null}
|
|
82
|
+
*/
|
|
83
|
+
species = null;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Whether the entity's `mesh_ground_covers` row is written in the current context.
|
|
87
|
+
* @type {boolean}
|
|
88
|
+
*/
|
|
89
|
+
written = false;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The geometry the row was last written for; null before the first write. The geometry itself and not
|
|
93
|
+
* its address on the device, which a geometry that replaces another can be given.
|
|
94
|
+
* @type {object|null}
|
|
95
|
+
*/
|
|
96
|
+
geometry = null;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether the member's ground is marked on the device where {@link corners} say it is.
|
|
100
|
+
* @type {boolean}
|
|
101
|
+
*/
|
|
102
|
+
placed = false;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The eight corners of the member's geometry box in its surface's frame, as last marked.
|
|
106
|
+
* @type {Float64Array}
|
|
107
|
+
*/
|
|
108
|
+
corners = new Float64Array(24);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The rectangle of {@link corners} on the frame's x and z: low x, low z, high x, high z.
|
|
112
|
+
* @type {Float64Array}
|
|
113
|
+
*/
|
|
114
|
+
rectangle = new Float64Array(4);
|
|
115
|
+
|
|
116
|
+
/** @type {function(): void} */
|
|
117
|
+
on_changed = null;
|
|
118
|
+
|
|
119
|
+
/** @type {function(): void} */
|
|
120
|
+
on_world = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* How far a corner of a member's box may be from where it was, in its surface's frame, before the member
|
|
125
|
+
* counts as moved and the ground under it is baked again: a micron. A surface that moves as one moves its
|
|
126
|
+
* members by the arithmetic's noise and no more, which for a world kilometres across is a ten-thousandth
|
|
127
|
+
* of this; nothing a surfel holds can show a move this small.
|
|
128
|
+
*
|
|
129
|
+
* @type {number}
|
|
130
|
+
*/
|
|
131
|
+
export const GRASS_MEMBER_MOVE_TOLERANCE = 1e-6;
|
|
132
|
+
|
|
133
|
+
const ONES = Float64Array.of(1, 1, 1);
|
|
134
|
+
|
|
135
|
+
const scratch_frame = new Float64Array(16);
|
|
136
|
+
const scratch_member = new Float64Array(16);
|
|
137
|
+
const scratch_low = new Float64Array(3);
|
|
138
|
+
const scratch_high = new Float64Array(3);
|
|
139
|
+
const scratch_corners = new Float64Array(24);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The corners of a member's geometry box, placed by the member's transform and read in its surface's frame.
|
|
143
|
+
*
|
|
144
|
+
* @param {Float64Array} corners the eight corners, written here
|
|
145
|
+
* @param {Float64Array} frame the surface's frame, frame to world: a rotation and a translation
|
|
146
|
+
* @param {MemberEntry} member
|
|
147
|
+
*/
|
|
148
|
+
function member_corners(corners, frame, member) {
|
|
149
|
+
const box = member.shaded.geometry.bounding_box;
|
|
150
|
+
const t = member.transform;
|
|
151
|
+
|
|
152
|
+
const m = scratch_member;
|
|
153
|
+
|
|
154
|
+
m4_from_rotation_translation_scale_array(
|
|
155
|
+
m,
|
|
156
|
+
t, TRANSFORM64_ROTATION_OFFSET,
|
|
157
|
+
t, TRANSFORM64_TRANSLATION_OFFSET,
|
|
158
|
+
t, TRANSFORM64_SCALE_OFFSET
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
for (let corner = 0; corner < 8; corner++) {
|
|
162
|
+
const x = box[(corner & 1) === 0 ? 0 : 3];
|
|
163
|
+
const y = box[(corner & 2) === 0 ? 1 : 4];
|
|
164
|
+
const z = box[(corner & 4) === 0 ? 2 : 5];
|
|
165
|
+
|
|
166
|
+
// into the world, and from the frame's origin
|
|
167
|
+
const wx = m[0] * x + m[4] * y + m[8] * z + m[12] - frame[12];
|
|
168
|
+
const wy = m[1] * x + m[5] * y + m[9] * z + m[13] - frame[13];
|
|
169
|
+
const wz = m[2] * x + m[6] * y + m[10] * z + m[14] - frame[14];
|
|
170
|
+
|
|
171
|
+
// onto the frame's axes
|
|
172
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
173
|
+
corners[corner * 3 + axis] = frame[axis * 4] * wx + frame[axis * 4 + 1] * wy + frame[axis * 4 + 2] * wz;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Keeps the scene's grass surfaces on the device: which entities are surfaces, which mesh rows are ground
|
|
180
|
+
* of which, and a box and a tallest blade for each surface, so that views can ask for its tiles.
|
|
181
|
+
*
|
|
182
|
+
* A surface is an entity with [{@link GrassSurface}, {@link Transform64}]; this system links those. Its
|
|
183
|
+
* members are the mesh entities whose {@link GroundCover} names it, which {@link GroundCoverSystem} links
|
|
184
|
+
* and hands over through {@link add_member}. A member may arrive before its surface, and waits.
|
|
185
|
+
*
|
|
186
|
+
* **What is written, and when.** Nothing per frame: a link, an unlink, an edit announced by a component's
|
|
187
|
+
* `onChanged`, and a move announced by the dataset queue the surface or member they touch, and
|
|
188
|
+
* {@link update} writes what is queued.
|
|
189
|
+
*
|
|
190
|
+
* - A member's `mesh_ground_covers` row, at the entity's own row: its surface's `transforms` row, the
|
|
191
|
+
* geometry a column traces for it, its species and density. Written once the mesh row itself exists.
|
|
192
|
+
* - A surface's record in {@link GPUGrassSurfaces}: a box, in the surface's frame, that holds every member
|
|
193
|
+
* whose row is written, as placed, and the tallest blade of any of their species. A surface with no such
|
|
194
|
+
* member has no record.
|
|
195
|
+
* - The ground that changed ({@link GPUGrassSurfaces#invalidate}): the rectangle of a member that has come,
|
|
196
|
+
* gone, changed geometry, or moved in its surface's frame by more than
|
|
197
|
+
* {@link GRASS_MEMBER_MOVE_TOLERANCE}. A surface that moves as one marks nothing.
|
|
198
|
+
* - A surface's `transforms` row is held, so that a surface entity with no mesh of its own has a frame on
|
|
199
|
+
* the device.
|
|
200
|
+
*
|
|
201
|
+
* **Rows need a device.** While the scene has no GPU context nothing is written, and when one arrives or
|
|
202
|
+
* is replaced everything is queued again.
|
|
203
|
+
*/
|
|
204
|
+
export class GrassSurfaceSystem extends System {
|
|
205
|
+
dependencies = [GrassSurface, Transform64];
|
|
206
|
+
|
|
207
|
+
/** @type {GraphicsEngine} */
|
|
208
|
+
#graphics;
|
|
209
|
+
|
|
210
|
+
/** @type {Scene} */
|
|
211
|
+
#scene;
|
|
212
|
+
|
|
213
|
+
/** @type {GPUSceneContext|null} */
|
|
214
|
+
#context = null;
|
|
215
|
+
|
|
216
|
+
/** @type {GPUGrassSurfaces|null} */
|
|
217
|
+
#gpu = null;
|
|
218
|
+
|
|
219
|
+
/** @type {GPUGrassBlades|null} */
|
|
220
|
+
#blades = null;
|
|
221
|
+
|
|
222
|
+
/** @type {GrassSurfaceExtension|null} */
|
|
223
|
+
#extension = null;
|
|
224
|
+
|
|
225
|
+
/** @type {GrassBladeExtension|null} */
|
|
226
|
+
#draw_extension = null;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The finest spacing the surfaces' `grass_surface_params` rows were written for.
|
|
230
|
+
* @type {number}
|
|
231
|
+
*/
|
|
232
|
+
#params_spacing = 0;
|
|
233
|
+
|
|
234
|
+
/** @type {Map<number, SurfaceEntry>} */
|
|
235
|
+
#surfaces = new Map();
|
|
236
|
+
|
|
237
|
+
/** @type {Map<number, MemberEntry>} */
|
|
238
|
+
#members = new Map();
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Members by the surface entity their cover names, whether or not that entity is a surface yet.
|
|
242
|
+
* @type {Map<number, Set<MemberEntry>>}
|
|
243
|
+
*/
|
|
244
|
+
#members_of = new Map();
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Surface entities whose record is to be written, or taken away if they are surfaces no longer.
|
|
248
|
+
* @type {Set<number>}
|
|
249
|
+
*/
|
|
250
|
+
#dirty_surfaces = new Set();
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Members whose row is to be written.
|
|
254
|
+
* @type {Set<MemberEntry>}
|
|
255
|
+
*/
|
|
256
|
+
#dirty_members = new Set();
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Each species in use: its index, how many members grow it, and the listener on its `onChanged`.
|
|
260
|
+
* @type {Map<GrassSpecies, {index: number, uses: number, on_changed: function(): void}>}
|
|
261
|
+
*/
|
|
262
|
+
#species = new Map();
|
|
263
|
+
|
|
264
|
+
/** @type {number[]} species indices given back */
|
|
265
|
+
#species_free = [];
|
|
266
|
+
|
|
267
|
+
/** @type {number} */
|
|
268
|
+
#species_next = 0;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {GraphicsEngine} graphics
|
|
272
|
+
* @param {Scene} scene
|
|
273
|
+
*/
|
|
274
|
+
constructor(graphics, scene) {
|
|
275
|
+
super();
|
|
276
|
+
|
|
277
|
+
assert.defined(graphics, 'graphics');
|
|
278
|
+
assert.defined(scene, 'scene');
|
|
279
|
+
|
|
280
|
+
this.#graphics = graphics;
|
|
281
|
+
this.#scene = scene;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @returns {Scene}
|
|
286
|
+
*/
|
|
287
|
+
get scene() {
|
|
288
|
+
return this.#scene;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* The surfaces on the device, or null while the scene has no GPU context.
|
|
293
|
+
*
|
|
294
|
+
* @returns {GPUGrassSurfaces|null}
|
|
295
|
+
*/
|
|
296
|
+
get surfaces() {
|
|
297
|
+
return this.#gpu;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* The blades on the device, or null while the scene has no GPU context.
|
|
302
|
+
*
|
|
303
|
+
* @returns {GPUGrassBlades|null}
|
|
304
|
+
*/
|
|
305
|
+
get blades() {
|
|
306
|
+
return this.#blades;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async startup(entityManager) {
|
|
310
|
+
this.entityManager = entityManager;
|
|
311
|
+
|
|
312
|
+
this.#extension = this.#graphics.add_extension(new GrassSurfaceExtension(this));
|
|
313
|
+
this.#draw_extension = this.#graphics.add_extension(new GrassBladeExtension(this));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async shutdown(entityManager) {
|
|
317
|
+
for (const entry of Array.from(this.#surfaces.values())) {
|
|
318
|
+
this.unlink(null, entry.transform, entry.entity);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (this.#extension !== null) {
|
|
322
|
+
this.#graphics.remove_extension(this.#extension);
|
|
323
|
+
this.#extension = null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (this.#draw_extension !== null) {
|
|
327
|
+
this.#graphics.remove_extension(this.#draw_extension);
|
|
328
|
+
this.#draw_extension = null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.#drop_context();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** The scene's rows are this dataset's entities; the first system to place one says so. */
|
|
335
|
+
handleDatasetAttached(dataset) {
|
|
336
|
+
assert.ok(this.#scene.dataset == null || this.#scene.dataset === dataset, 'scene belongs to another dataset');
|
|
337
|
+
|
|
338
|
+
this.#scene.dataset = dataset;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
handleDatasetDetached(dataset) {
|
|
342
|
+
if (this.#scene.dataset === dataset) {
|
|
343
|
+
this.#scene.dataset = null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @param {GrassSurface} surface
|
|
349
|
+
* @param {Transform64} transform
|
|
350
|
+
* @param {number} entity
|
|
351
|
+
*/
|
|
352
|
+
link(surface, transform, entity) {
|
|
353
|
+
const entry = new SurfaceEntry();
|
|
354
|
+
|
|
355
|
+
entry.entity = entity;
|
|
356
|
+
entry.transform = transform;
|
|
357
|
+
|
|
358
|
+
entry.on_world = () => {
|
|
359
|
+
if (entry.held) {
|
|
360
|
+
this.#context.rows.mark_world(entity);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// the members are where they were; what they are in the frame is not
|
|
364
|
+
this.#dirty_surfaces.add(entity);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
entry.on_local = () => {
|
|
368
|
+
if (entry.held) {
|
|
369
|
+
this.#context.rows.mark_local(entity);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
entry.on_components = ({ klass }) => {
|
|
374
|
+
if (klass === TransformAttachment) {
|
|
375
|
+
entry.on_local();
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const dataset = this.entityManager.dataset;
|
|
380
|
+
|
|
381
|
+
dataset.addEntityEventListener(entity, TRANSFORM64_EVENT_CHANGE, entry.on_world);
|
|
382
|
+
dataset.addEntityEventListener(entity, TRANSFORM_ATTACHMENT_EVENT_CHANGE, entry.on_local);
|
|
383
|
+
dataset.addEntityEventListener(entity, EventType.ComponentAdded, entry.on_components);
|
|
384
|
+
dataset.addEntityEventListener(entity, EventType.ComponentRemoved, entry.on_components);
|
|
385
|
+
|
|
386
|
+
this.#surfaces.set(entity, entry);
|
|
387
|
+
this.#dirty_surfaces.add(entity);
|
|
388
|
+
|
|
389
|
+
// members that came first can be written now
|
|
390
|
+
this.#queue_members_of(entity);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* @param {GrassSurface} surface
|
|
395
|
+
* @param {Transform64} transform
|
|
396
|
+
* @param {number} entity
|
|
397
|
+
*/
|
|
398
|
+
unlink(surface, transform, entity) {
|
|
399
|
+
const entry = this.#surfaces.get(entity);
|
|
400
|
+
|
|
401
|
+
if (entry === undefined) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const dataset = this.entityManager.dataset;
|
|
406
|
+
|
|
407
|
+
dataset.removeEntityEventListener(entity, TRANSFORM64_EVENT_CHANGE, entry.on_world);
|
|
408
|
+
dataset.removeEntityEventListener(entity, TRANSFORM_ATTACHMENT_EVENT_CHANGE, entry.on_local);
|
|
409
|
+
dataset.removeEntityEventListener(entity, EventType.ComponentAdded, entry.on_components);
|
|
410
|
+
dataset.removeEntityEventListener(entity, EventType.ComponentRemoved, entry.on_components);
|
|
411
|
+
|
|
412
|
+
this.#surfaces.delete(entity);
|
|
413
|
+
|
|
414
|
+
// a context that has been replaced took its rows with it; only the one that is running is handed anything back
|
|
415
|
+
if (this.#context !== null && this.#context === this.#graphics.scene_context(this.#scene)) {
|
|
416
|
+
if (entry.held) {
|
|
417
|
+
this.#context.rows.release(entity);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.#gpu.remove(row_of_entity(entity));
|
|
421
|
+
this.#clear_params(row_of_entity(entity), this.#context);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
entry.held = false;
|
|
425
|
+
|
|
426
|
+
this.#dirty_surfaces.delete(entity);
|
|
427
|
+
|
|
428
|
+
// its members are ground of nothing until it is a surface again
|
|
429
|
+
this.#queue_members_of(entity);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* A mesh entity becomes ground of the surface its cover names.
|
|
434
|
+
*
|
|
435
|
+
* @param {number} entity
|
|
436
|
+
* @param {GroundCover} cover
|
|
437
|
+
* @param {ShadedGeometry} shaded
|
|
438
|
+
* @param {Transform64} transform
|
|
439
|
+
*/
|
|
440
|
+
add_member(entity, cover, shaded, transform) {
|
|
441
|
+
assert.isNonNegativeInteger(entity, 'entity');
|
|
442
|
+
assert.equal(this.#members.has(entity), false, 'entity is a member already');
|
|
443
|
+
|
|
444
|
+
const member = new MemberEntry();
|
|
445
|
+
|
|
446
|
+
member.entity = entity;
|
|
447
|
+
member.cover = cover;
|
|
448
|
+
member.shaded = shaded;
|
|
449
|
+
member.transform = transform;
|
|
450
|
+
|
|
451
|
+
member.on_changed = () => {
|
|
452
|
+
this.#dirty_members.add(member);
|
|
453
|
+
this.#dirty_surfaces.add(cover.surface);
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
member.on_world = () => {
|
|
457
|
+
this.#dirty_surfaces.add(cover.surface);
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
cover.onChanged.add(member.on_changed);
|
|
461
|
+
|
|
462
|
+
const dataset = this.entityManager.dataset;
|
|
463
|
+
|
|
464
|
+
dataset.addEntityEventListener(entity, TRANSFORM64_EVENT_CHANGE, member.on_world);
|
|
465
|
+
dataset.addEntityEventListener(entity, SHADED_GEOMETRY_EVENT_CHANGE, member.on_changed);
|
|
466
|
+
|
|
467
|
+
this.#members.set(entity, member);
|
|
468
|
+
|
|
469
|
+
let set = this.#members_of.get(cover.surface);
|
|
470
|
+
|
|
471
|
+
if (set === undefined) {
|
|
472
|
+
set = new Set();
|
|
473
|
+
|
|
474
|
+
this.#members_of.set(cover.surface, set);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
set.add(member);
|
|
478
|
+
|
|
479
|
+
this.#species_take(member);
|
|
480
|
+
|
|
481
|
+
member.on_changed();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* A mesh entity stops being ground.
|
|
486
|
+
*
|
|
487
|
+
* @param {number} entity one that is no member is left alone
|
|
488
|
+
*/
|
|
489
|
+
remove_member(entity) {
|
|
490
|
+
const member = this.#members.get(entity);
|
|
491
|
+
|
|
492
|
+
if (member === undefined) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const cover = member.cover;
|
|
497
|
+
|
|
498
|
+
cover.onChanged.remove(member.on_changed);
|
|
499
|
+
|
|
500
|
+
const dataset = this.entityManager.dataset;
|
|
501
|
+
|
|
502
|
+
dataset.removeEntityEventListener(entity, TRANSFORM64_EVENT_CHANGE, member.on_world);
|
|
503
|
+
dataset.removeEntityEventListener(entity, SHADED_GEOMETRY_EVENT_CHANGE, member.on_changed);
|
|
504
|
+
|
|
505
|
+
this.#members.delete(entity);
|
|
506
|
+
this.#dirty_members.delete(member);
|
|
507
|
+
|
|
508
|
+
const set = this.#members_of.get(cover.surface);
|
|
509
|
+
|
|
510
|
+
set.delete(member);
|
|
511
|
+
|
|
512
|
+
if (set.size === 0) {
|
|
513
|
+
this.#members_of.delete(cover.surface);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
this.#species_give(member);
|
|
517
|
+
|
|
518
|
+
if (member.written && this.#context !== null && this.#context === this.#graphics.scene_context(this.#scene)) {
|
|
519
|
+
this.#context.scene_database.get('mesh_ground_covers').remove(row_of_entity(entity));
|
|
520
|
+
|
|
521
|
+
this.#unplace(member);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
member.written = false;
|
|
525
|
+
member.placed = false;
|
|
526
|
+
|
|
527
|
+
this.#dirty_surfaces.add(cover.surface);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* @param {number} surface a surface entity
|
|
532
|
+
*/
|
|
533
|
+
#queue_members_of(surface) {
|
|
534
|
+
const set = this.#members_of.get(surface);
|
|
535
|
+
|
|
536
|
+
if (set === undefined) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
for (const member of set) {
|
|
541
|
+
this.#dirty_members.add(member);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Count a member under its cover's species, which gets an index when it is first used.
|
|
547
|
+
*
|
|
548
|
+
* @param {MemberEntry} member
|
|
549
|
+
*/
|
|
550
|
+
#species_take(member) {
|
|
551
|
+
const species = member.cover.species;
|
|
552
|
+
|
|
553
|
+
member.species = species;
|
|
554
|
+
|
|
555
|
+
if (species === null) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
let record = this.#species.get(species);
|
|
560
|
+
|
|
561
|
+
if (record === undefined) {
|
|
562
|
+
const index = this.#species_free.length > 0 ? this.#species_free.pop() : this.#species_next++;
|
|
563
|
+
|
|
564
|
+
record = {
|
|
565
|
+
index,
|
|
566
|
+
uses: 0,
|
|
567
|
+
// a blade's length reaches every surface it grows on
|
|
568
|
+
on_changed: () => {
|
|
569
|
+
this.#push_species(species, index);
|
|
570
|
+
|
|
571
|
+
for (const other of this.#members.values()) {
|
|
572
|
+
if (other.species === species) {
|
|
573
|
+
other.on_changed();
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
species.onChanged.add(record.on_changed);
|
|
580
|
+
|
|
581
|
+
this.#species.set(species, record);
|
|
582
|
+
|
|
583
|
+
this.#push_species(species, index);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
record.uses++;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Write a species' record on the device, if there is a device.
|
|
591
|
+
*
|
|
592
|
+
* @param {GrassSpecies} species
|
|
593
|
+
* @param {number} index
|
|
594
|
+
*/
|
|
595
|
+
#push_species(species, index) {
|
|
596
|
+
if (this.#blades !== null) {
|
|
597
|
+
this.#blades.set_species(index, species);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Take a surface's `grass_surface_params` row away, if it has one.
|
|
603
|
+
*
|
|
604
|
+
* @param {number} row
|
|
605
|
+
* @param {GPUSceneContext} context
|
|
606
|
+
*/
|
|
607
|
+
#clear_params(row, context) {
|
|
608
|
+
const table = context.scene_database.get('grass_surface_params');
|
|
609
|
+
|
|
610
|
+
if (table.occupancy.get(row)) {
|
|
611
|
+
table.remove(row);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* @param {MemberEntry} member
|
|
617
|
+
*/
|
|
618
|
+
#species_give(member) {
|
|
619
|
+
const species = member.species;
|
|
620
|
+
|
|
621
|
+
member.species = null;
|
|
622
|
+
|
|
623
|
+
if (species === null) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const record = this.#species.get(species);
|
|
628
|
+
|
|
629
|
+
if (--record.uses === 0) {
|
|
630
|
+
species.onChanged.remove(record.on_changed);
|
|
631
|
+
|
|
632
|
+
this.#species.delete(species);
|
|
633
|
+
this.#species_free.push(record.index);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* The index a species in use is known by on the device.
|
|
639
|
+
*
|
|
640
|
+
* @param {GrassSpecies} species
|
|
641
|
+
* @returns {number} -1 for a species no member grows
|
|
642
|
+
*/
|
|
643
|
+
species_index(species) {
|
|
644
|
+
const record = this.#species.get(species);
|
|
645
|
+
|
|
646
|
+
return record === undefined ? -1 : record.index;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
#drop_context() {
|
|
650
|
+
if (this.#blades !== null) {
|
|
651
|
+
this.#blades.destroy();
|
|
652
|
+
this.#blades = null;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (this.#gpu !== null) {
|
|
656
|
+
this.#gpu.destroy();
|
|
657
|
+
this.#gpu = null;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
this.#context = null;
|
|
661
|
+
|
|
662
|
+
for (const entry of this.#surfaces.values()) {
|
|
663
|
+
entry.held = false;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
for (const member of this.#members.values()) {
|
|
667
|
+
member.written = false;
|
|
668
|
+
member.placed = false;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* A member's ground is no longer where it was marked: the tiles under it are to be baked again.
|
|
674
|
+
*
|
|
675
|
+
* @param {MemberEntry} member
|
|
676
|
+
*/
|
|
677
|
+
#unplace(member) {
|
|
678
|
+
if (!member.placed) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
member.placed = false;
|
|
683
|
+
|
|
684
|
+
if (this.#surfaces.has(member.cover.surface)) {
|
|
685
|
+
const r = member.rectangle;
|
|
686
|
+
|
|
687
|
+
this.#gpu.invalidate(row_of_entity(member.cover.surface), r[0], r[1], r[2], r[3]);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
update(time_delta_seconds) {
|
|
692
|
+
const context = this.#graphics.scene_context(this.#scene);
|
|
693
|
+
|
|
694
|
+
if (context === null) {
|
|
695
|
+
// no device: before the first start, or after a stop
|
|
696
|
+
if (this.#context !== null) {
|
|
697
|
+
this.#drop_context();
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (context !== this.#context) {
|
|
704
|
+
// a new device took every row and buffer with the old one: everything is written again
|
|
705
|
+
const settings = this.#gpu?.settings;
|
|
706
|
+
const press = this.#blades?.press;
|
|
707
|
+
|
|
708
|
+
this.#drop_context();
|
|
709
|
+
|
|
710
|
+
this.#context = context;
|
|
711
|
+
this.#gpu = new GPUGrassSurfaces(context.graphics);
|
|
712
|
+
|
|
713
|
+
if (settings !== undefined) {
|
|
714
|
+
this.#gpu.settings = settings;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
this.#blades = new GPUGrassBlades(context.graphics, this.#gpu);
|
|
718
|
+
|
|
719
|
+
if (press !== undefined) {
|
|
720
|
+
this.#blades.press.enabled = press.enabled;
|
|
721
|
+
this.#blades.press.spacing = press.spacing;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
for (const [species, record] of this.#species) {
|
|
725
|
+
this.#push_species(species, record.index);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
for (const entity of this.#surfaces.keys()) {
|
|
729
|
+
this.#dirty_surfaces.add(entity);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
for (const member of this.#members.values()) {
|
|
733
|
+
this.#dirty_members.add(member);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (this.#params_spacing !== this.#gpu.settings.finest_spacing) {
|
|
738
|
+
// the lattices are cut from the surfels' spacing: every surface's row is written again
|
|
739
|
+
this.#params_spacing = this.#gpu.settings.finest_spacing;
|
|
740
|
+
|
|
741
|
+
for (const entity of this.#surfaces.keys()) {
|
|
742
|
+
this.#dirty_surfaces.add(entity);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
for (const member of this.#dirty_members) {
|
|
747
|
+
if (this.#write_member(member, context)) {
|
|
748
|
+
this.#dirty_members.delete(member);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
for (const entity of this.#dirty_surfaces) {
|
|
753
|
+
this.#write_surface(entity, context);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
this.#dirty_surfaces.clear();
|
|
757
|
+
|
|
758
|
+
this.#gpu.update();
|
|
759
|
+
this.#blades.update(time_delta_seconds);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Bring a member's `mesh_ground_covers` row up to date.
|
|
764
|
+
*
|
|
765
|
+
* @param {MemberEntry} member
|
|
766
|
+
* @param {GPUSceneContext} context
|
|
767
|
+
* @returns {boolean} false when the row has to wait for the entity's mesh row
|
|
768
|
+
*/
|
|
769
|
+
#write_member(member, context) {
|
|
770
|
+
const covers = context.scene_database.get('mesh_ground_covers');
|
|
771
|
+
const row = row_of_entity(member.entity);
|
|
772
|
+
const cover = member.cover;
|
|
773
|
+
|
|
774
|
+
if (member.species !== cover.species) {
|
|
775
|
+
this.#species_give(member);
|
|
776
|
+
this.#species_take(member);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (!this.#surfaces.has(cover.surface)) {
|
|
780
|
+
// ground of nothing, for now
|
|
781
|
+
if (member.written) {
|
|
782
|
+
covers.remove(row);
|
|
783
|
+
|
|
784
|
+
member.written = false;
|
|
785
|
+
member.placed = false;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const geometry = member.shaded.geometry;
|
|
792
|
+
|
|
793
|
+
if (!context.rows.has_mesh(member.entity) || !context.geometries.has(geometry)) {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const species = cover.species;
|
|
798
|
+
const address = context.geometries.getAddress(geometry);
|
|
799
|
+
|
|
800
|
+
if (member.written && member.geometry !== geometry) {
|
|
801
|
+
// other ground, in the same place
|
|
802
|
+
this.#unplace(member);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
covers.set(row, {
|
|
806
|
+
flags: MESH_GROUND_COVER_FLAG_MEMBER | (species !== null ? MESH_GROUND_COVER_FLAG_GROWS : 0),
|
|
807
|
+
surface: row_of_entity(cover.surface),
|
|
808
|
+
geometry: address,
|
|
809
|
+
species: species !== null ? this.#species.get(species).index : 0,
|
|
810
|
+
density: Math.min(1, Math.max(0, cover.density)),
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
member.written = true;
|
|
814
|
+
member.geometry = geometry;
|
|
815
|
+
|
|
816
|
+
// its surface's box holds it from now, and the ground under it is marked
|
|
817
|
+
this.#dirty_surfaces.add(cover.surface);
|
|
818
|
+
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Bring a surface's record up to date, or take it away when the entity is a surface no longer or has no member.
|
|
824
|
+
*
|
|
825
|
+
* @param {number} entity
|
|
826
|
+
* @param {GPUSceneContext} context
|
|
827
|
+
*/
|
|
828
|
+
#write_surface(entity, context) {
|
|
829
|
+
const entry = this.#surfaces.get(entity);
|
|
830
|
+
const row = row_of_entity(entity);
|
|
831
|
+
|
|
832
|
+
if (entry === undefined) {
|
|
833
|
+
// unlinked since it was queued, and taken away there
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (!entry.held) {
|
|
838
|
+
context.rows.acquire(entity);
|
|
839
|
+
|
|
840
|
+
entry.held = true;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const members = this.#members_of.get(entity);
|
|
844
|
+
|
|
845
|
+
if (members === undefined) {
|
|
846
|
+
this.#gpu.remove(row);
|
|
847
|
+
this.#clear_params(row, context);
|
|
848
|
+
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const t = entry.transform;
|
|
853
|
+
const frame = scratch_frame;
|
|
854
|
+
|
|
855
|
+
// where the entity is and how it is turned; its scale is no part of the frame
|
|
856
|
+
m4_from_rotation_translation_scale_array(
|
|
857
|
+
frame,
|
|
858
|
+
t, TRANSFORM64_ROTATION_OFFSET,
|
|
859
|
+
t, TRANSFORM64_TRANSLATION_OFFSET,
|
|
860
|
+
ONES, 0
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
const low = scratch_low.fill(Infinity);
|
|
864
|
+
const high = scratch_high.fill(-Infinity);
|
|
865
|
+
|
|
866
|
+
const corners = scratch_corners;
|
|
867
|
+
|
|
868
|
+
let blade_length = 0;
|
|
869
|
+
let blade_length_min = Infinity;
|
|
870
|
+
let blade_width_min = Infinity;
|
|
871
|
+
let density = 0;
|
|
872
|
+
let cover = 0;
|
|
873
|
+
let held = 0;
|
|
874
|
+
|
|
875
|
+
for (const member of members) {
|
|
876
|
+
if (!member.written) {
|
|
877
|
+
// no column can find it yet
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
member_corners(corners, frame, member);
|
|
882
|
+
|
|
883
|
+
for (let i = 0; i < 24; i++) {
|
|
884
|
+
const axis = i % 3;
|
|
885
|
+
const v = corners[i];
|
|
886
|
+
|
|
887
|
+
if (v < low[axis]) {
|
|
888
|
+
low[axis] = v;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (v > high[axis]) {
|
|
892
|
+
high[axis] = v;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
this.#place(row, member, corners);
|
|
897
|
+
|
|
898
|
+
const species = member.cover.species;
|
|
899
|
+
|
|
900
|
+
if (species !== null) {
|
|
901
|
+
blade_length = Math.max(blade_length, species.blade_length);
|
|
902
|
+
blade_length_min = Math.min(blade_length_min, species.blade_length);
|
|
903
|
+
blade_width_min = Math.min(blade_width_min, species.blade_width);
|
|
904
|
+
density = Math.max(density, species.density);
|
|
905
|
+
cover = Math.max(cover, species.density * species.blade_width);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
held++;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
if (held === 0) {
|
|
912
|
+
this.#gpu.remove(row);
|
|
913
|
+
this.#clear_params(row, context);
|
|
914
|
+
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
this.#gpu.set(row, low, high, blade_length);
|
|
919
|
+
|
|
920
|
+
if (density > 0) {
|
|
921
|
+
context.scene_database.get('grass_surface_params').set(row, {
|
|
922
|
+
lattice_bits: grass_surface_lattice_bits(density, this.#gpu.settings.finest_spacing),
|
|
923
|
+
density,
|
|
924
|
+
blade_length,
|
|
925
|
+
blade_length_min,
|
|
926
|
+
blade_width_min,
|
|
927
|
+
cover,
|
|
928
|
+
});
|
|
929
|
+
} else {
|
|
930
|
+
this.#clear_params(row, context);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Mark a member's ground where it is, if that is not where it was marked: the tiles under where it was
|
|
936
|
+
* and under where it is are baked again. A member that has moved with its surface is where it was.
|
|
937
|
+
*
|
|
938
|
+
* @param {number} surface the surface's `transforms` row
|
|
939
|
+
* @param {MemberEntry} member
|
|
940
|
+
* @param {Float64Array} corners the member's corners in the surface's frame
|
|
941
|
+
*/
|
|
942
|
+
#place(surface, member, corners) {
|
|
943
|
+
const was = member.corners;
|
|
944
|
+
|
|
945
|
+
if (member.placed) {
|
|
946
|
+
let moved = false;
|
|
947
|
+
|
|
948
|
+
for (let i = 0; i < 24; i++) {
|
|
949
|
+
if (Math.abs(corners[i] - was[i]) > GRASS_MEMBER_MOVE_TOLERANCE) {
|
|
950
|
+
moved = true;
|
|
951
|
+
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
if (!moved) {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
this.#unplace(member);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
was.set(corners);
|
|
964
|
+
|
|
965
|
+
const r = member.rectangle;
|
|
966
|
+
|
|
967
|
+
r[0] = Infinity;
|
|
968
|
+
r[1] = Infinity;
|
|
969
|
+
r[2] = -Infinity;
|
|
970
|
+
r[3] = -Infinity;
|
|
971
|
+
|
|
972
|
+
for (let corner = 0; corner < 8; corner++) {
|
|
973
|
+
const x = corners[corner * 3];
|
|
974
|
+
const z = corners[corner * 3 + 2];
|
|
975
|
+
|
|
976
|
+
r[0] = Math.min(r[0], x);
|
|
977
|
+
r[1] = Math.min(r[1], z);
|
|
978
|
+
r[2] = Math.max(r[2], x);
|
|
979
|
+
r[3] = Math.max(r[3], z);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
member.placed = true;
|
|
983
|
+
|
|
984
|
+
this.#gpu.invalidate(surface, r[0], r[1], r[2], r[3]);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Record the frame's asks and bakes for one view.
|
|
989
|
+
*
|
|
990
|
+
* @param {import("../../shade/renderer/extension/FrameContext.js").FrameContext} frame
|
|
991
|
+
*/
|
|
992
|
+
record(frame) {
|
|
993
|
+
if (this.#gpu === null || frame.view.scene !== this.#context) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
this.#gpu.graph_update({ graph: frame.graph, view: frame.view });
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Record a view's blades, made and drawn into the frame's G-buffer. The blades are made here and not
|
|
1002
|
+
* at the frame's start because they are bent by the scene's wind, which its producer publishes at the
|
|
1003
|
+
* frame's start.
|
|
1004
|
+
*
|
|
1005
|
+
* The blades are pressed by the obstacles of the entity manager's {@link GPUFluidSystem}, when it has
|
|
1006
|
+
* one for this scene.
|
|
1007
|
+
*
|
|
1008
|
+
* @param {FrameContext} frame
|
|
1009
|
+
*/
|
|
1010
|
+
draw(frame) {
|
|
1011
|
+
if (this.#blades === null || frame.view.scene !== this.#context) {
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
const fluid = this.entityManager?.getSystem(GPUFluidSystem) ?? null;
|
|
1016
|
+
const forcing = fluid !== null && fluid.scene === this.#scene ? fluid.forcing : null;
|
|
1017
|
+
|
|
1018
|
+
this.#blades.graph_generate({ graph: frame.graph, view: frame.view, forcing });
|
|
1019
|
+
this.#blades.graph_draw(frame);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* The blades' seat in the frame: where the G-buffer is written into, ahead of what is laid over surfaces.
|
|
1025
|
+
*/
|
|
1026
|
+
export class GrassBladeExtension extends RenderExtension {
|
|
1027
|
+
name = "grass blades";
|
|
1028
|
+
|
|
1029
|
+
phase = FramePhase.AfterGBuffer;
|
|
1030
|
+
|
|
1031
|
+
/** @type {GrassSurfaceSystem} */
|
|
1032
|
+
#system;
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* @param {GrassSurfaceSystem} system
|
|
1036
|
+
*/
|
|
1037
|
+
constructor(system) {
|
|
1038
|
+
super();
|
|
1039
|
+
|
|
1040
|
+
this.#system = system;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
record(frame) {
|
|
1044
|
+
this.#system.draw(frame);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* The grass surfaces' seat in the frame: at its start, where the compute that later phases read belongs.
|
|
1050
|
+
*/
|
|
1051
|
+
export class GrassSurfaceExtension extends RenderExtension {
|
|
1052
|
+
name = "grass surfaces";
|
|
1053
|
+
|
|
1054
|
+
phase = FramePhase.FrameStart;
|
|
1055
|
+
|
|
1056
|
+
/** @type {GrassSurfaceSystem} */
|
|
1057
|
+
#system;
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* @param {GrassSurfaceSystem} system
|
|
1061
|
+
*/
|
|
1062
|
+
constructor(system) {
|
|
1063
|
+
super();
|
|
1064
|
+
|
|
1065
|
+
this.#system = system;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
record(frame) {
|
|
1069
|
+
this.#system.record(frame);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
enquirePipelines(enquiry) {
|
|
1073
|
+
GPUGrassSurfaces.enquirePipelines(enquiry);
|
|
1074
|
+
GPUGrassBlades.enquirePipelines(enquiry);
|
|
1075
|
+
}
|
|
1076
|
+
}
|