@thunderclap-engine/engine 0.0.0-stage → 1.1.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 +390 -0
- package/LICENSE +21 -0
- package/README.md +333 -2
- package/dist/analytics/analytics.d.ts +80 -0
- package/dist/analytics/analytics.js +129 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.js +1 -0
- package/dist/anim/aim.d.ts +43 -0
- package/dist/anim/aim.js +157 -0
- package/dist/anim/clip.d.ts +98 -0
- package/dist/anim/clip.js +282 -0
- package/dist/anim/compress.d.ts +65 -0
- package/dist/anim/compress.js +339 -0
- package/dist/anim/foot-ik.d.ts +74 -0
- package/dist/anim/foot-ik.js +241 -0
- package/dist/anim/graph.d.ts +153 -0
- package/dist/anim/graph.js +532 -0
- package/dist/anim/ik.d.ts +105 -0
- package/dist/anim/ik.js +435 -0
- package/dist/anim/index.d.ts +36 -0
- package/dist/anim/index.js +21 -0
- package/dist/anim/match.d.ts +66 -0
- package/dist/anim/match.js +153 -0
- package/dist/anim/mixer.d.ts +113 -0
- package/dist/anim/mixer.js +314 -0
- package/dist/anim/morph.d.ts +41 -0
- package/dist/anim/morph.js +94 -0
- package/dist/anim/pose.d.ts +74 -0
- package/dist/anim/pose.js +254 -0
- package/dist/anim/quat.d.ts +44 -0
- package/dist/anim/quat.js +187 -0
- package/dist/anim/retarget.d.ts +97 -0
- package/dist/anim/retarget.js +366 -0
- package/dist/anim/root-motion.d.ts +44 -0
- package/dist/anim/root-motion.js +224 -0
- package/dist/anim/skin-pose.d.ts +39 -0
- package/dist/anim/skin-pose.js +53 -0
- package/dist/anim/socket.d.ts +47 -0
- package/dist/anim/socket.js +84 -0
- package/dist/anim/spring-chain.d.ts +73 -0
- package/dist/anim/spring-chain.js +294 -0
- package/dist/assets/atlas.d.ts +90 -0
- package/dist/assets/atlas.js +212 -0
- package/dist/assets/baked.d.ts +33 -0
- package/dist/assets/baked.js +38 -0
- package/dist/assets/bundle.d.ts +88 -0
- package/dist/assets/bundle.js +464 -0
- package/dist/assets/cache.d.ts +56 -0
- package/dist/assets/cache.js +123 -0
- package/dist/assets/gltf-load.d.ts +252 -0
- package/dist/assets/gltf-load.js +661 -0
- package/dist/assets/gltf-skin.d.ts +36 -0
- package/dist/assets/gltf-skin.js +109 -0
- package/dist/assets/gltf.d.ts +706 -0
- package/dist/assets/gltf.js +1376 -0
- package/dist/assets/index.d.ts +20 -0
- package/dist/assets/index.js +10 -0
- package/dist/assets/ktx2.d.ts +71 -0
- package/dist/assets/ktx2.js +213 -0
- package/dist/assets/manifest.d.ts +79 -0
- package/dist/assets/manifest.js +7 -0
- package/dist/assets/meshopt.d.ts +23 -0
- package/dist/assets/meshopt.js +403 -0
- package/dist/audio/audio.d.ts +733 -0
- package/dist/audio/audio.js +2013 -0
- package/dist/audio/dsp.d.ts +61 -0
- package/dist/audio/dsp.js +159 -0
- package/dist/audio/duck.d.ts +44 -0
- package/dist/audio/duck.js +101 -0
- package/dist/audio/envelope.d.ts +53 -0
- package/dist/audio/envelope.js +106 -0
- package/dist/audio/index.d.ts +13 -0
- package/dist/audio/index.js +14 -0
- package/dist/audio/music.d.ts +113 -0
- package/dist/audio/music.js +548 -0
- package/dist/audio/occlusion.d.ts +55 -0
- package/dist/audio/occlusion.js +61 -0
- package/dist/audio/persist.d.ts +23 -0
- package/dist/audio/persist.js +27 -0
- package/dist/audio/recipes.d.ts +55 -0
- package/dist/audio/recipes.js +227 -0
- package/dist/audio/send.d.ts +41 -0
- package/dist/audio/send.js +118 -0
- package/dist/audio/sprites.d.ts +59 -0
- package/dist/audio/sprites.js +43 -0
- package/dist/audio/synth.d.ts +103 -0
- package/dist/audio/synth.js +197 -0
- package/dist/audio/variations.d.ts +25 -0
- package/dist/audio/variations.js +55 -0
- package/dist/audio/zones.d.ts +100 -0
- package/dist/audio/zones.js +167 -0
- package/dist/core/detached-surface.d.ts +44 -0
- package/dist/core/detached-surface.js +104 -0
- package/dist/core/events.d.ts +24 -0
- package/dist/core/events.js +43 -0
- package/dist/core/game.d.ts +409 -0
- package/dist/core/game.js +530 -0
- package/dist/core/hash.d.ts +24 -0
- package/dist/core/hash.js +49 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +9 -0
- package/dist/core/loop.d.ts +113 -0
- package/dist/core/loop.js +185 -0
- package/dist/core/math.d.ts +58 -0
- package/dist/core/math.js +210 -0
- package/dist/core/noise.d.ts +40 -0
- package/dist/core/noise.js +247 -0
- package/dist/core/pool.d.ts +42 -0
- package/dist/core/pool.js +85 -0
- package/dist/core/random.d.ts +61 -0
- package/dist/core/random.js +199 -0
- package/dist/core/scene.d.ts +79 -0
- package/dist/core/scene.js +195 -0
- package/dist/core/timer.d.ts +66 -0
- package/dist/core/timer.js +286 -0
- package/dist/fx/billboard-wgsl.d.ts +29 -0
- package/dist/fx/billboard-wgsl.js +158 -0
- package/dist/fx/billboard.d.ts +249 -0
- package/dist/fx/billboard.js +702 -0
- package/dist/fx/debug-draw.d.ts +127 -0
- package/dist/fx/debug-draw.js +523 -0
- package/dist/fx/debug-wgsl.d.ts +7 -0
- package/dist/fx/debug-wgsl.js +32 -0
- package/dist/fx/decals-wgsl.d.ts +15 -0
- package/dist/fx/decals-wgsl.js +173 -0
- package/dist/fx/decals.d.ts +216 -0
- package/dist/fx/decals.js +607 -0
- package/dist/fx/effect.d.ts +129 -0
- package/dist/fx/effect.js +349 -0
- package/dist/fx/effects/hit-spark.json +48 -0
- package/dist/fx/effects/index.d.ts +8 -0
- package/dist/fx/effects/index.js +9 -0
- package/dist/fx/effects/magic-aura.json +47 -0
- package/dist/fx/effects/smoke-puff.json +34 -0
- package/dist/fx/emit-surface.d.ts +40 -0
- package/dist/fx/emit-surface.js +124 -0
- package/dist/fx/flicker.d.ts +30 -0
- package/dist/fx/flicker.js +42 -0
- package/dist/fx/index.d.ts +31 -0
- package/dist/fx/index.js +20 -0
- package/dist/fx/particles-wgsl.d.ts +57 -0
- package/dist/fx/particles-wgsl.js +828 -0
- package/dist/fx/particles.d.ts +566 -0
- package/dist/fx/particles.js +1533 -0
- package/dist/fx/random.d.ts +15 -0
- package/dist/fx/random.js +20 -0
- package/dist/fx/sky-wgsl.d.ts +23 -0
- package/dist/fx/sky-wgsl.js +127 -0
- package/dist/fx/sky.d.ts +96 -0
- package/dist/fx/sky.js +175 -0
- package/dist/fx/text-atlas.d.ts +143 -0
- package/dist/fx/text-atlas.js +327 -0
- package/dist/fx/trail-wgsl.d.ts +11 -0
- package/dist/fx/trail-wgsl.js +42 -0
- package/dist/fx/trail.d.ts +194 -0
- package/dist/fx/trail.js +555 -0
- package/dist/fx/water-wgsl.d.ts +34 -0
- package/dist/fx/water-wgsl.js +197 -0
- package/dist/fx/water.d.ts +176 -0
- package/dist/fx/water.js +371 -0
- package/dist/geom/collide/bvh.d.ts +151 -0
- package/dist/geom/collide/bvh.js +493 -0
- package/dist/geom/collide/debug.d.ts +14 -0
- package/dist/geom/collide/debug.js +74 -0
- package/dist/geom/collide/grid.d.ts +26 -0
- package/dist/geom/collide/grid.js +91 -0
- package/dist/geom/collide/index.d.ts +8 -0
- package/dist/geom/collide/index.js +8 -0
- package/dist/geom/collide/queries.d.ts +70 -0
- package/dist/geom/collide/queries.js +583 -0
- package/dist/geom/collide/serialize.d.ts +14 -0
- package/dist/geom/collide/serialize.js +145 -0
- package/dist/geom/collide/shapes.d.ts +161 -0
- package/dist/geom/collide/shapes.js +686 -0
- package/dist/geom/collide/slide.d.ts +66 -0
- package/dist/geom/collide/slide.js +375 -0
- package/dist/geom/collide/tile-slide.d.ts +88 -0
- package/dist/geom/collide/tile-slide.js +255 -0
- package/dist/geom/geometry.d.ts +95 -0
- package/dist/geom/geometry.js +322 -0
- package/dist/geom/heightfield.d.ts +72 -0
- package/dist/geom/heightfield.js +295 -0
- package/dist/geom/hull.d.ts +27 -0
- package/dist/geom/hull.js +279 -0
- package/dist/geom/index.d.ts +35 -0
- package/dist/geom/index.js +23 -0
- package/dist/geom/iso.d.ts +74 -0
- package/dist/geom/iso.js +89 -0
- package/dist/geom/lod.d.ts +29 -0
- package/dist/geom/lod.js +27 -0
- package/dist/geom/ops.d.ts +47 -0
- package/dist/geom/ops.js +285 -0
- package/dist/geom/primitives.d.ts +97 -0
- package/dist/geom/primitives.js +359 -0
- package/dist/geom/shapes.d.ts +43 -0
- package/dist/geom/shapes.js +88 -0
- package/dist/geom/simplify.d.ts +38 -0
- package/dist/geom/simplify.js +519 -0
- package/dist/geom/split.d.ts +37 -0
- package/dist/geom/split.js +413 -0
- package/dist/geom/sweep.d.ts +83 -0
- package/dist/geom/sweep.js +534 -0
- package/dist/geom/tangents.d.ts +16 -0
- package/dist/geom/tangents.js +124 -0
- package/dist/geom/triangulate.d.ts +19 -0
- package/dist/geom/triangulate.js +147 -0
- package/dist/host/default.d.ts +10 -0
- package/dist/host/default.js +10 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +3 -0
- package/dist/host/types.d.ts +144 -0
- package/dist/host/types.js +1 -0
- package/dist/host/web-links.d.ts +38 -0
- package/dist/host/web-links.js +110 -0
- package/dist/host/web.d.ts +30 -0
- package/dist/host/web.js +216 -0
- package/dist/host/xr.d.ts +24 -0
- package/dist/host/xr.js +59 -0
- package/dist/i18n/i18n.d.ts +59 -0
- package/dist/i18n/i18n.js +241 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +3 -0
- package/dist/i18n/message.d.ts +72 -0
- package/dist/i18n/message.js +369 -0
- package/dist/i18n/negotiate.d.ts +17 -0
- package/dist/i18n/negotiate.js +58 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -0
- package/dist/input/bindings.d.ts +31 -0
- package/dist/input/bindings.js +141 -0
- package/dist/input/clock.d.ts +44 -0
- package/dist/input/clock.js +49 -0
- package/dist/input/follow.d.ts +133 -0
- package/dist/input/follow.js +218 -0
- package/dist/input/gestures.d.ts +281 -0
- package/dist/input/gestures.js +662 -0
- package/dist/input/glyphs.d.ts +35 -0
- package/dist/input/glyphs.js +216 -0
- package/dist/input/gyro.d.ts +85 -0
- package/dist/input/gyro.js +140 -0
- package/dist/input/index.d.ts +19 -0
- package/dist/input/index.js +16 -0
- package/dist/input/input.d.ts +543 -0
- package/dist/input/input.js +1492 -0
- package/dist/input/look.d.ts +327 -0
- package/dist/input/look.js +681 -0
- package/dist/input/magnify.d.ts +177 -0
- package/dist/input/magnify.js +131 -0
- package/dist/input/pointer-dispatch.d.ts +138 -0
- package/dist/input/pointer-dispatch.js +180 -0
- package/dist/input/pointer-router.d.ts +204 -0
- package/dist/input/pointer-router.js +533 -0
- package/dist/input/pointer-sources.d.ts +164 -0
- package/dist/input/pointer-sources.js +306 -0
- package/dist/input/rays.d.ts +138 -0
- package/dist/input/rays.js +615 -0
- package/dist/input/record.d.ts +209 -0
- package/dist/input/record.js +601 -0
- package/dist/input/touch-zones.d.ts +147 -0
- package/dist/input/touch-zones.js +300 -0
- package/dist/input/types.d.ts +158 -0
- package/dist/input/types.js +1 -0
- package/dist/input/xr-source.d.ts +53 -0
- package/dist/input/xr-source.js +164 -0
- package/dist/nav/astar.d.ts +45 -0
- package/dist/nav/astar.js +182 -0
- package/dist/nav/corridor.d.ts +40 -0
- package/dist/nav/corridor.js +95 -0
- package/dist/nav/crowd.d.ts +94 -0
- package/dist/nav/crowd.js +624 -0
- package/dist/nav/flow.d.ts +61 -0
- package/dist/nav/flow.js +193 -0
- package/dist/nav/grid.d.ts +108 -0
- package/dist/nav/grid.js +210 -0
- package/dist/nav/heap.d.ts +22 -0
- package/dist/nav/heap.js +92 -0
- package/dist/nav/index.d.ts +37 -0
- package/dist/nav/index.js +19 -0
- package/dist/nav/mesh/areas.d.ts +44 -0
- package/dist/nav/mesh/areas.js +98 -0
- package/dist/nav/mesh/bake-options.d.ts +33 -0
- package/dist/nav/mesh/bake-options.js +76 -0
- package/dist/nav/mesh/contour.d.ts +22 -0
- package/dist/nav/mesh/contour.js +323 -0
- package/dist/nav/mesh/flow3.d.ts +35 -0
- package/dist/nav/mesh/flow3.js +229 -0
- package/dist/nav/mesh/links.d.ts +38 -0
- package/dist/nav/mesh/links.js +72 -0
- package/dist/nav/mesh/mesh-path.d.ts +152 -0
- package/dist/nav/mesh/mesh-path.js +643 -0
- package/dist/nav/mesh/mesh-reach.d.ts +78 -0
- package/dist/nav/mesh/mesh-reach.js +450 -0
- package/dist/nav/mesh/navmesh.d.ts +117 -0
- package/dist/nav/mesh/navmesh.js +647 -0
- package/dist/nav/mesh/polymesh.d.ts +24 -0
- package/dist/nav/mesh/polymesh.js +384 -0
- package/dist/nav/mesh/regions.d.ts +12 -0
- package/dist/nav/mesh/regions.js +367 -0
- package/dist/nav/mesh/serialize.d.ts +13 -0
- package/dist/nav/mesh/serialize.js +197 -0
- package/dist/nav/mesh/voxelize.d.ts +111 -0
- package/dist/nav/mesh/voxelize.js +552 -0
- package/dist/nav/obstacles.d.ts +75 -0
- package/dist/nav/obstacles.js +294 -0
- package/dist/nav/path.d.ts +59 -0
- package/dist/nav/path.js +177 -0
- package/dist/nav/query-queue.d.ts +46 -0
- package/dist/nav/query-queue.js +308 -0
- package/dist/nav/reach.d.ts +53 -0
- package/dist/nav/reach.js +148 -0
- package/dist/nav/steer.d.ts +36 -0
- package/dist/nav/steer.js +78 -0
- package/dist/platform/boot.d.ts +28 -0
- package/dist/platform/boot.js +43 -0
- package/dist/platform/device-mode.d.ts +40 -0
- package/dist/platform/device-mode.js +104 -0
- package/dist/platform/device.d.ts +31 -0
- package/dist/platform/device.js +91 -0
- package/dist/platform/environment.d.ts +42 -0
- package/dist/platform/environment.js +82 -0
- package/dist/platform/gpu.d.ts +40 -0
- package/dist/platform/gpu.js +57 -0
- package/dist/platform/index.d.ts +18 -0
- package/dist/platform/index.js +10 -0
- package/dist/platform/letterbox.d.ts +43 -0
- package/dist/platform/letterbox.js +57 -0
- package/dist/platform/links.d.ts +20 -0
- package/dist/platform/links.js +43 -0
- package/dist/platform/screens.d.ts +36 -0
- package/dist/platform/screens.js +138 -0
- package/dist/platform/surface.d.ts +72 -0
- package/dist/platform/surface.js +157 -0
- package/dist/platform/xr-fake.d.ts +168 -0
- package/dist/platform/xr-fake.js +434 -0
- package/dist/platform/xr-surface.d.ts +120 -0
- package/dist/platform/xr-surface.js +214 -0
- package/dist/platform/xr-types.d.ts +262 -0
- package/dist/post/ao.d.ts +12 -0
- package/dist/post/ao.js +136 -0
- package/dist/post/blend.d.ts +27 -0
- package/dist/post/blend.js +129 -0
- package/dist/post/depth-pass.d.ts +43 -0
- package/dist/post/depth-pass.js +118 -0
- package/dist/post/dof.d.ts +1 -0
- package/dist/post/dof.js +66 -0
- package/dist/post/exposure.d.ts +80 -0
- package/dist/post/exposure.js +322 -0
- package/dist/post/index.d.ts +12 -0
- package/dist/post/index.js +11 -0
- package/dist/post/lens-dirt.d.ts +13 -0
- package/dist/post/lens-dirt.js +91 -0
- package/dist/post/lut.d.ts +19 -0
- package/dist/post/lut.js +50 -0
- package/dist/post/motion-blur.d.ts +9 -0
- package/dist/post/motion-blur.js +78 -0
- package/dist/post/post-stack.d.ts +302 -0
- package/dist/post/post-stack.js +1137 -0
- package/dist/post/settings.d.ts +485 -0
- package/dist/post/settings.js +416 -0
- package/dist/post/shaders.d.ts +25 -0
- package/dist/post/shaders.js +410 -0
- package/dist/post/ssr.d.ts +16 -0
- package/dist/post/ssr.js +155 -0
- package/dist/post/taa.d.ts +74 -0
- package/dist/post/taa.js +235 -0
- package/dist/post/white-balance.d.ts +25 -0
- package/dist/post/white-balance.js +98 -0
- package/dist/render/bindings.d.ts +98 -0
- package/dist/render/bindings.js +281 -0
- package/dist/render/blend.d.ts +13 -0
- package/dist/render/blend.js +26 -0
- package/dist/render/camera-2d.d.ts +72 -0
- package/dist/render/camera-2d.js +92 -0
- package/dist/render/camera.d.ts +302 -0
- package/dist/render/camera.js +671 -0
- package/dist/render/color.d.ts +16 -0
- package/dist/render/color.js +41 -0
- package/dist/render/compressed.d.ts +104 -0
- package/dist/render/compressed.js +248 -0
- package/dist/render/diagnostics.d.ts +15 -0
- package/dist/render/diagnostics.js +43 -0
- package/dist/render/dynamic-resolution.d.ts +70 -0
- package/dist/render/dynamic-resolution.js +126 -0
- package/dist/render/fake-gpu.d.ts +204 -0
- package/dist/render/fake-gpu.js +426 -0
- package/dist/render/flipbook.d.ts +56 -0
- package/dist/render/flipbook.js +87 -0
- package/dist/render/frame.d.ts +278 -0
- package/dist/render/frame.js +174 -0
- package/dist/render/fullscreen.d.ts +54 -0
- package/dist/render/fullscreen.js +91 -0
- package/dist/render/gpu-timer.d.ts +73 -0
- package/dist/render/gpu-timer.js +186 -0
- package/dist/render/index.d.ts +53 -0
- package/dist/render/index.js +29 -0
- package/dist/render/instance-list.d.ts +185 -0
- package/dist/render/instance-list.js +547 -0
- package/dist/render/lights.d.ts +181 -0
- package/dist/render/lights.js +233 -0
- package/dist/render/lod.d.ts +54 -0
- package/dist/render/lod.js +52 -0
- package/dist/render/material.d.ts +165 -0
- package/dist/render/material.js +292 -0
- package/dist/render/mesh.d.ts +284 -0
- package/dist/render/mesh.js +472 -0
- package/dist/render/mipmap.d.ts +16 -0
- package/dist/render/mipmap.js +121 -0
- package/dist/render/parallax.d.ts +50 -0
- package/dist/render/parallax.js +47 -0
- package/dist/render/pbr-wgsl.d.ts +31 -0
- package/dist/render/pbr-wgsl.js +119 -0
- package/dist/render/ping-pong.d.ts +42 -0
- package/dist/render/ping-pong.js +74 -0
- package/dist/render/renderer.d.ts +741 -0
- package/dist/render/renderer.js +2486 -0
- package/dist/render/scene-pipelines.d.ts +44 -0
- package/dist/render/scene-pipelines.js +92 -0
- package/dist/render/scene-target.d.ts +170 -0
- package/dist/render/scene-target.js +450 -0
- package/dist/render/shadow.d.ts +74 -0
- package/dist/render/shadow.js +208 -0
- package/dist/render/skin.d.ts +112 -0
- package/dist/render/skin.js +240 -0
- package/dist/render/snapshot.d.ts +36 -0
- package/dist/render/snapshot.js +34 -0
- package/dist/render/standard.d.ts +162 -0
- package/dist/render/standard.js +263 -0
- package/dist/render/texture.d.ts +142 -0
- package/dist/render/texture.js +228 -0
- package/dist/render/tile-layer.d.ts +110 -0
- package/dist/render/tile-layer.js +304 -0
- package/dist/render/transform.d.ts +115 -0
- package/dist/render/transform.js +318 -0
- package/dist/render/wgsl.d.ts +131 -0
- package/dist/render/wgsl.js +528 -0
- package/dist/save/codec.d.ts +49 -0
- package/dist/save/codec.js +169 -0
- package/dist/save/index.d.ts +8 -0
- package/dist/save/index.js +8 -0
- package/dist/save/journal.d.ts +24 -0
- package/dist/save/journal.js +102 -0
- package/dist/save/migrate.d.ts +15 -0
- package/dist/save/migrate.js +37 -0
- package/dist/save/schema.d.ts +72 -0
- package/dist/save/schema.js +154 -0
- package/dist/save/settings.d.ts +28 -0
- package/dist/save/settings.js +59 -0
- package/dist/save/slots.d.ts +56 -0
- package/dist/save/slots.js +200 -0
- package/dist/save/storage.d.ts +35 -0
- package/dist/save/storage.js +62 -0
- package/dist/save/store.d.ts +114 -0
- package/dist/save/store.js +269 -0
- package/dist/testing/fake-host.d.ts +103 -0
- package/dist/testing/fake-host.js +163 -0
- package/dist/testing/fixed-clock.d.ts +25 -0
- package/dist/testing/fixed-clock.js +30 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/test-game.d.ts +76 -0
- package/dist/testing/test-game.js +92 -0
- package/dist/tween/ease.d.ts +77 -0
- package/dist/tween/ease.js +192 -0
- package/dist/tween/index.d.ts +8 -0
- package/dist/tween/index.js +7 -0
- package/dist/tween/timeline.d.ts +78 -0
- package/dist/tween/timeline.js +269 -0
- package/dist/tween/tween.d.ts +168 -0
- package/dist/tween/tween.js +320 -0
- package/dist/ui/anchor.d.ts +206 -0
- package/dist/ui/anchor.js +307 -0
- package/dist/ui/caption.d.ts +122 -0
- package/dist/ui/caption.js +286 -0
- package/dist/ui/cursor.d.ts +105 -0
- package/dist/ui/cursor.js +261 -0
- package/dist/ui/dom.d.ts +30 -0
- package/dist/ui/dom.js +92 -0
- package/dist/ui/floats.d.ts +86 -0
- package/dist/ui/floats.js +260 -0
- package/dist/ui/hud.d.ts +198 -0
- package/dist/ui/hud.js +431 -0
- package/dist/ui/index.d.ts +37 -0
- package/dist/ui/index.js +34 -0
- package/dist/ui/inventory-card.d.ts +52 -0
- package/dist/ui/inventory-card.js +173 -0
- package/dist/ui/inventory-context.d.ts +29 -0
- package/dist/ui/inventory-context.js +125 -0
- package/dist/ui/inventory-drag.d.ts +63 -0
- package/dist/ui/inventory-drag.js +394 -0
- package/dist/ui/inventory-grid.d.ts +66 -0
- package/dist/ui/inventory-grid.js +625 -0
- package/dist/ui/inventory-radial.d.ts +39 -0
- package/dist/ui/inventory-radial.js +168 -0
- package/dist/ui/inventory.d.ts +128 -0
- package/dist/ui/inventory.js +154 -0
- package/dist/ui/layout.d.ts +356 -0
- package/dist/ui/layout.js +856 -0
- package/dist/ui/link.d.ts +64 -0
- package/dist/ui/link.js +155 -0
- package/dist/ui/loading.d.ts +40 -0
- package/dist/ui/loading.js +157 -0
- package/dist/ui/loupe.d.ts +74 -0
- package/dist/ui/loupe.js +164 -0
- package/dist/ui/menu-nav.d.ts +33 -0
- package/dist/ui/menu-nav.js +28 -0
- package/dist/ui/minimap-canvas.d.ts +145 -0
- package/dist/ui/minimap-canvas.js +460 -0
- package/dist/ui/notify.d.ts +40 -0
- package/dist/ui/notify.js +141 -0
- package/dist/ui/orb.d.ts +53 -0
- package/dist/ui/orb.js +304 -0
- package/dist/ui/overlay.d.ts +213 -0
- package/dist/ui/overlay.js +394 -0
- package/dist/ui/padnav.d.ts +53 -0
- package/dist/ui/padnav.js +146 -0
- package/dist/ui/perf.d.ts +130 -0
- package/dist/ui/perf.js +329 -0
- package/dist/ui/rotate-card.d.ts +54 -0
- package/dist/ui/rotate-card.js +97 -0
- package/dist/ui/stack.d.ts +128 -0
- package/dist/ui/stack.js +312 -0
- package/dist/ui/styles.d.ts +13 -0
- package/dist/ui/styles.js +200 -0
- package/dist/ui/text-scale.d.ts +67 -0
- package/dist/ui/text-scale.js +102 -0
- package/dist/ui/theme.d.ts +70 -0
- package/dist/ui/theme.js +98 -0
- package/dist/ui/toast.d.ts +23 -0
- package/dist/ui/toast.js +46 -0
- package/dist/ui/tooltip.d.ts +89 -0
- package/dist/ui/tooltip.js +333 -0
- package/dist/ui/widgets-2.d.ts +134 -0
- package/dist/ui/widgets-2.js +399 -0
- package/dist/ui/widgets-3.d.ts +91 -0
- package/dist/ui/widgets-3.js +212 -0
- package/dist/ui/widgets.d.ts +34 -0
- package/dist/ui/widgets.js +50 -0
- package/dist/ui/world-panel/index.d.ts +5 -0
- package/dist/ui/world-panel/index.js +5 -0
- package/dist/ui/world-panel/layout.d.ts +38 -0
- package/dist/ui/world-panel/layout.js +68 -0
- package/dist/ui/world-panel/paint.d.ts +96 -0
- package/dist/ui/world-panel/paint.js +136 -0
- package/dist/ui/world-panel/panel.d.ts +235 -0
- package/dist/ui/world-panel/panel.js +762 -0
- package/dist/ui/world-panel/wgsl.d.ts +10 -0
- package/dist/ui/world-panel/wgsl.js +52 -0
- package/dist/ui/world-panel/widgets.d.ts +207 -0
- package/dist/ui/world-panel/widgets.js +569 -0
- package/dist/voxel/chunks.d.ts +77 -0
- package/dist/voxel/chunks.js +149 -0
- package/dist/voxel/grid.d.ts +84 -0
- package/dist/voxel/grid.js +223 -0
- package/dist/voxel/index.d.ts +22 -0
- package/dist/voxel/index.js +7 -0
- package/dist/voxel/mesher-worker.d.ts +14 -0
- package/dist/voxel/mesher-worker.js +47 -0
- package/dist/voxel/mesher.d.ts +73 -0
- package/dist/voxel/mesher.js +306 -0
- package/dist/voxel/ray.d.ts +32 -0
- package/dist/voxel/ray.js +73 -0
- package/dist/voxel/wgsl.d.ts +16 -0
- package/dist/voxel/wgsl.js +28 -0
- package/dist/voxel/worker-client.d.ts +79 -0
- package/dist/voxel/worker-client.js +122 -0
- package/package.json +177 -3
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { VERTEX_LAYOUT_3D } from '../render/mesh.js';
|
|
2
|
+
import { Transform } from '../render/transform.js';
|
|
3
|
+
import { createVoxelMesher } from './worker-client.js';
|
|
4
|
+
const defaultNow = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
|
|
5
|
+
const coords = [0, 0, 0];
|
|
6
|
+
export function createVoxelChunks(renderer, grid, opts) {
|
|
7
|
+
const material = opts.material;
|
|
8
|
+
const slack = Math.max(1, opts.slack ?? 1.5);
|
|
9
|
+
const minQuads = Math.max(1, opts.minQuads ?? 64);
|
|
10
|
+
const ownMesher = !opts.mesher;
|
|
11
|
+
const mesher = opts.mesher ?? createVoxelMesher(grid, opts);
|
|
12
|
+
const now = opts.now ?? defaultNow;
|
|
13
|
+
const params = opts.params;
|
|
14
|
+
const count = grid.chunkCount;
|
|
15
|
+
const meshes = new Array(count).fill(null);
|
|
16
|
+
const transforms = new Array(count);
|
|
17
|
+
const ox = opts.origin?.[0] ?? 0;
|
|
18
|
+
const oy = opts.origin?.[1] ?? 0;
|
|
19
|
+
const oz = opts.origin?.[2] ?? 0;
|
|
20
|
+
/** World centre and radius of each chunk's last sphere. */
|
|
21
|
+
const centers = new Float32Array(count * 3);
|
|
22
|
+
const radii = new Float32Array(count);
|
|
23
|
+
const requestedAt = new Float64Array(count);
|
|
24
|
+
const finished = [];
|
|
25
|
+
const stats = {
|
|
26
|
+
drawn: 0,
|
|
27
|
+
culled: 0,
|
|
28
|
+
triangles: 0,
|
|
29
|
+
chunks: 0,
|
|
30
|
+
growths: 0,
|
|
31
|
+
pending: 0,
|
|
32
|
+
remeshes: 0,
|
|
33
|
+
remeshMs: 0,
|
|
34
|
+
};
|
|
35
|
+
let disposed = false;
|
|
36
|
+
for (let c = 0; c < count; c++) {
|
|
37
|
+
grid.chunkCoords(c, coords);
|
|
38
|
+
transforms[c] = new Transform({
|
|
39
|
+
x: ox + coords[0] * grid.chunk,
|
|
40
|
+
y: oy + coords[1] * grid.chunk,
|
|
41
|
+
z: oz + coords[2] * grid.chunk,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const apply = (reply) => {
|
|
45
|
+
const c = reply.chunk;
|
|
46
|
+
let mesh = meshes[c];
|
|
47
|
+
if (reply.indexCount === 0) {
|
|
48
|
+
if (mesh && mesh.indexCount > 0) {
|
|
49
|
+
mesh.update({ vertexCount: 0, indexCount: 0 });
|
|
50
|
+
stats.chunks--;
|
|
51
|
+
}
|
|
52
|
+
radii[c] = 0;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!mesh) {
|
|
56
|
+
const quads = Math.max(minQuads, Math.ceil((reply.indexCount / 6) * slack));
|
|
57
|
+
mesh = renderer.createMesh({
|
|
58
|
+
label: `voxel-chunk-${c}`,
|
|
59
|
+
layout: VERTEX_LAYOUT_3D,
|
|
60
|
+
capacity: { vertices: quads * 4, indices: quads * 6 },
|
|
61
|
+
indexFormat: 'uint32',
|
|
62
|
+
autoBounds: false,
|
|
63
|
+
bounds: { center: [0, 0, 0], radius: Infinity },
|
|
64
|
+
});
|
|
65
|
+
meshes[c] = mesh;
|
|
66
|
+
}
|
|
67
|
+
const wasEmpty = mesh.indexCount === 0;
|
|
68
|
+
mesh.update(reply);
|
|
69
|
+
if (wasEmpty)
|
|
70
|
+
stats.chunks++;
|
|
71
|
+
const t = transforms[c].position;
|
|
72
|
+
const b = reply.bounds;
|
|
73
|
+
centers[c * 3] = t.x + b.center[0];
|
|
74
|
+
centers[c * 3 + 1] = t.y + b.center[1];
|
|
75
|
+
centers[c * 3 + 2] = t.z + b.center[2];
|
|
76
|
+
radii[c] = b.radius;
|
|
77
|
+
};
|
|
78
|
+
const onReply = (reply) => {
|
|
79
|
+
if (!disposed)
|
|
80
|
+
finished.push(reply);
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
grid,
|
|
84
|
+
material,
|
|
85
|
+
mesher,
|
|
86
|
+
meshes,
|
|
87
|
+
transforms,
|
|
88
|
+
stats,
|
|
89
|
+
update() {
|
|
90
|
+
let applied = 0;
|
|
91
|
+
const clock = now();
|
|
92
|
+
while (finished.length > 0) {
|
|
93
|
+
const reply = finished.shift();
|
|
94
|
+
apply(reply);
|
|
95
|
+
applied++;
|
|
96
|
+
stats.pending--;
|
|
97
|
+
stats.remeshes++;
|
|
98
|
+
stats.remeshMs = clock - requestedAt[reply.chunk];
|
|
99
|
+
}
|
|
100
|
+
grid.forEachDirtyChunk((c) => {
|
|
101
|
+
requestedAt[c] = clock;
|
|
102
|
+
stats.pending++;
|
|
103
|
+
void mesher.remesh(c).then(onReply);
|
|
104
|
+
});
|
|
105
|
+
let growths = 0;
|
|
106
|
+
for (let c = 0; c < count; c++) {
|
|
107
|
+
const m = meshes[c];
|
|
108
|
+
if (m)
|
|
109
|
+
growths += m.growths;
|
|
110
|
+
}
|
|
111
|
+
stats.growths = growths;
|
|
112
|
+
return applied;
|
|
113
|
+
},
|
|
114
|
+
draw(frame, camera) {
|
|
115
|
+
let drawn = 0;
|
|
116
|
+
let culled = 0;
|
|
117
|
+
let triangles = 0;
|
|
118
|
+
for (let c = 0; c < count; c++) {
|
|
119
|
+
const mesh = meshes[c];
|
|
120
|
+
if (!mesh || mesh.indexCount === 0)
|
|
121
|
+
continue;
|
|
122
|
+
if (!camera.seesSphere(centers[c * 3], centers[c * 3 + 1], centers[c * 3 + 2], radii[c])) {
|
|
123
|
+
culled++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (params)
|
|
127
|
+
frame.mesh(mesh, material, transforms[c], params);
|
|
128
|
+
else
|
|
129
|
+
frame.mesh(mesh, material, transforms[c]);
|
|
130
|
+
drawn++;
|
|
131
|
+
triangles += mesh.indexCount / 3;
|
|
132
|
+
}
|
|
133
|
+
stats.drawn = drawn;
|
|
134
|
+
stats.culled = culled;
|
|
135
|
+
stats.triangles = triangles;
|
|
136
|
+
return stats;
|
|
137
|
+
},
|
|
138
|
+
dispose() {
|
|
139
|
+
disposed = true;
|
|
140
|
+
finished.length = 0;
|
|
141
|
+
for (let c = 0; c < count; c++) {
|
|
142
|
+
meshes[c]?.destroy();
|
|
143
|
+
meshes[c] = null;
|
|
144
|
+
}
|
|
145
|
+
if (ownMesher)
|
|
146
|
+
mesher.dispose();
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The block grid: one `Uint8Array` of block ids (0 = air) over a box of `sizeX × sizeY × sizeZ`
|
|
3
|
+
* cells, cut into cubic chunks of `chunk` cells on a side. Cell (x, y, z) lives at
|
|
4
|
+
* `x + sizeX * (y + sizeY * z)`; chunk (cx, cy, cz) is `cx + chunksX * (cy + chunksY * cz)`.
|
|
5
|
+
* Every `set` bumps `version` and flags the chunk it touched, plus the chunks sharing that
|
|
6
|
+
* cell's faces, edges and corners when it lies on a border (a face there changes the
|
|
7
|
+
* neighbour's ambient occlusion). `serialize()` packs the grid into one `ArrayBuffer` a Worker
|
|
8
|
+
* can own (`deserializeVoxelGrid`), so the mesher runs off the thread on its own copy.
|
|
9
|
+
* Pure: no GPU, no DOM.
|
|
10
|
+
*/
|
|
11
|
+
export interface VoxelGridOptions {
|
|
12
|
+
sizeX: number;
|
|
13
|
+
sizeY: number;
|
|
14
|
+
sizeZ: number;
|
|
15
|
+
/** Cells on a chunk's side. Default 16. The sizes need not be multiples of it. */
|
|
16
|
+
chunk?: number;
|
|
17
|
+
}
|
|
18
|
+
/** What a grid reports to its subscribers (`VoxelGrid.subscribe`). */
|
|
19
|
+
export interface VoxelGridListener {
|
|
20
|
+
/** One cell changed to `block`. */
|
|
21
|
+
set?(x: number, y: number, z: number, block: number): void;
|
|
22
|
+
/** Every cell may have changed (`fill`, `deserialize`): resync whole. */
|
|
23
|
+
reset?(): void;
|
|
24
|
+
}
|
|
25
|
+
export interface VoxelGrid {
|
|
26
|
+
readonly sizeX: number;
|
|
27
|
+
readonly sizeY: number;
|
|
28
|
+
readonly sizeZ: number;
|
|
29
|
+
/** Cells on a chunk's side. */
|
|
30
|
+
readonly chunk: number;
|
|
31
|
+
readonly chunksX: number;
|
|
32
|
+
readonly chunksY: number;
|
|
33
|
+
readonly chunksZ: number;
|
|
34
|
+
/** Chunks in the grid (`chunksX * chunksY * chunksZ`). */
|
|
35
|
+
readonly chunkCount: number;
|
|
36
|
+
/** The cells, `x + sizeX * (y + sizeY * z)`. Writing it directly bypasses the dirty flags. */
|
|
37
|
+
readonly data: Uint8Array;
|
|
38
|
+
/** Bumps on every change (`set`, `setMany`, `fill`, `deserialize`). */
|
|
39
|
+
readonly version: number;
|
|
40
|
+
/** Dirty flag per chunk (1 = needs a remesh). */
|
|
41
|
+
readonly dirty: Uint8Array;
|
|
42
|
+
inBounds(x: number, y: number, z: number): boolean;
|
|
43
|
+
/** The cell's index in `data`; no bounds check. */
|
|
44
|
+
index(x: number, y: number, z: number): number;
|
|
45
|
+
/** The block at (x, y, z); `outside` (default 0) when out of bounds. */
|
|
46
|
+
get(x: number, y: number, z: number, outside?: number): number;
|
|
47
|
+
/** Set one cell; out of bounds is ignored. Returns whether the cell changed. */
|
|
48
|
+
set(x: number, y: number, z: number, block: number): boolean;
|
|
49
|
+
/** Set cells from a flat `[x, y, z, block, ...]` list. Returns how many changed. */
|
|
50
|
+
setMany(cells: ArrayLike<number>): number;
|
|
51
|
+
/** Every cell from `fn`; flags every chunk dirty. */
|
|
52
|
+
fill(fn: (x: number, y: number, z: number) => number): void;
|
|
53
|
+
/** Index of the chunk holding cell (x, y, z), -1 out of bounds. */
|
|
54
|
+
chunkAt(x: number, y: number, z: number): number;
|
|
55
|
+
/** Chunk index from chunk coordinates; no bounds check. */
|
|
56
|
+
chunkIndex(cx: number, cy: number, cz: number): number;
|
|
57
|
+
/** Chunk coordinates of a chunk index, into `out` (`[cx, cy, cz]`). */
|
|
58
|
+
chunkCoords(chunk: number, out: number[] | Float32Array | Int32Array): void;
|
|
59
|
+
/** True when no cell of the chunk is a block. */
|
|
60
|
+
chunkEmpty(chunk: number): boolean;
|
|
61
|
+
isDirty(chunk: number): boolean;
|
|
62
|
+
markDirty(chunk: number): void;
|
|
63
|
+
/** Flag every chunk. */
|
|
64
|
+
markAllDirty(): void;
|
|
65
|
+
clearDirty(chunk: number): void;
|
|
66
|
+
/** Calls `fn` for each dirty chunk, clearing its flag first; returns how many. */
|
|
67
|
+
forEachDirtyChunk(fn: (chunk: number) => void): number;
|
|
68
|
+
/**
|
|
69
|
+
* One `ArrayBuffer`: a 16-byte header (sizeX, sizeY, sizeZ, chunk as uint32) then the
|
|
70
|
+
* cells. Transferable; `deserializeVoxelGrid` rebuilds the grid from it.
|
|
71
|
+
*/
|
|
72
|
+
serialize(): ArrayBuffer;
|
|
73
|
+
/** Copy the cells of a serialized grid of the same sizes into this one; every chunk dirty. */
|
|
74
|
+
deserialize(buffer: ArrayBuffer): void;
|
|
75
|
+
/** Mirror changes elsewhere (a mesher Worker). Returns the unsubscriber. */
|
|
76
|
+
subscribe(listener: VoxelGridListener): () => void;
|
|
77
|
+
}
|
|
78
|
+
/** A grid of air. */
|
|
79
|
+
export declare function createVoxelGrid(opts: VoxelGridOptions): VoxelGrid;
|
|
80
|
+
/**
|
|
81
|
+
* A grid over the cells of a `serialize()` buffer: the grid reads and writes that buffer in
|
|
82
|
+
* place (no copy), so a Worker handed the transferred buffer owns the cells.
|
|
83
|
+
*/
|
|
84
|
+
export declare function deserializeVoxelGrid(buffer: ArrayBuffer): VoxelGrid;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The block grid: one `Uint8Array` of block ids (0 = air) over a box of `sizeX × sizeY × sizeZ`
|
|
3
|
+
* cells, cut into cubic chunks of `chunk` cells on a side. Cell (x, y, z) lives at
|
|
4
|
+
* `x + sizeX * (y + sizeY * z)`; chunk (cx, cy, cz) is `cx + chunksX * (cy + chunksY * cz)`.
|
|
5
|
+
* Every `set` bumps `version` and flags the chunk it touched, plus the chunks sharing that
|
|
6
|
+
* cell's faces, edges and corners when it lies on a border (a face there changes the
|
|
7
|
+
* neighbour's ambient occlusion). `serialize()` packs the grid into one `ArrayBuffer` a Worker
|
|
8
|
+
* can own (`deserializeVoxelGrid`), so the mesher runs off the thread on its own copy.
|
|
9
|
+
* Pure: no GPU, no DOM.
|
|
10
|
+
*/
|
|
11
|
+
const HEADER_BYTES = 16;
|
|
12
|
+
class Grid {
|
|
13
|
+
sizeX;
|
|
14
|
+
sizeY;
|
|
15
|
+
sizeZ;
|
|
16
|
+
chunk;
|
|
17
|
+
chunksX;
|
|
18
|
+
chunksY;
|
|
19
|
+
chunksZ;
|
|
20
|
+
chunkCount;
|
|
21
|
+
data;
|
|
22
|
+
dirty;
|
|
23
|
+
version = 0;
|
|
24
|
+
listeners = [];
|
|
25
|
+
constructor(opts, data) {
|
|
26
|
+
const chunk = opts.chunk ?? 16;
|
|
27
|
+
if (!(chunk >= 1) || !(opts.sizeX >= 1) || !(opts.sizeY >= 1) || !(opts.sizeZ >= 1)) {
|
|
28
|
+
throw new Error('createVoxelGrid: sizes and chunk must be at least 1');
|
|
29
|
+
}
|
|
30
|
+
this.sizeX = Math.floor(opts.sizeX);
|
|
31
|
+
this.sizeY = Math.floor(opts.sizeY);
|
|
32
|
+
this.sizeZ = Math.floor(opts.sizeZ);
|
|
33
|
+
this.chunk = Math.floor(chunk);
|
|
34
|
+
this.chunksX = Math.ceil(this.sizeX / this.chunk);
|
|
35
|
+
this.chunksY = Math.ceil(this.sizeY / this.chunk);
|
|
36
|
+
this.chunksZ = Math.ceil(this.sizeZ / this.chunk);
|
|
37
|
+
this.chunkCount = this.chunksX * this.chunksY * this.chunksZ;
|
|
38
|
+
this.data = data ?? new Uint8Array(this.sizeX * this.sizeY * this.sizeZ);
|
|
39
|
+
this.dirty = new Uint8Array(this.chunkCount).fill(1);
|
|
40
|
+
}
|
|
41
|
+
inBounds(x, y, z) {
|
|
42
|
+
return x >= 0 && y >= 0 && z >= 0 && x < this.sizeX && y < this.sizeY && z < this.sizeZ;
|
|
43
|
+
}
|
|
44
|
+
index(x, y, z) {
|
|
45
|
+
return x + this.sizeX * (y + this.sizeY * z);
|
|
46
|
+
}
|
|
47
|
+
get(x, y, z, outside = 0) {
|
|
48
|
+
if (!this.inBounds(x, y, z))
|
|
49
|
+
return outside;
|
|
50
|
+
return this.data[x + this.sizeX * (y + this.sizeY * z)];
|
|
51
|
+
}
|
|
52
|
+
set(x, y, z, block) {
|
|
53
|
+
if (!this.inBounds(x, y, z))
|
|
54
|
+
return false;
|
|
55
|
+
const i = this.index(x, y, z);
|
|
56
|
+
if (this.data[i] === block)
|
|
57
|
+
return false;
|
|
58
|
+
this.data[i] = block;
|
|
59
|
+
this.version++;
|
|
60
|
+
this.touch(x, y, z);
|
|
61
|
+
for (const l of this.listeners)
|
|
62
|
+
l.set?.(x, y, z, block);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
setMany(cells) {
|
|
66
|
+
let changed = 0;
|
|
67
|
+
for (let i = 0; i + 3 < cells.length; i += 4) {
|
|
68
|
+
if (this.set(cells[i], cells[i + 1], cells[i + 2], cells[i + 3]))
|
|
69
|
+
changed++;
|
|
70
|
+
}
|
|
71
|
+
return changed;
|
|
72
|
+
}
|
|
73
|
+
fill(fn) {
|
|
74
|
+
const d = this.data;
|
|
75
|
+
let i = 0;
|
|
76
|
+
for (let z = 0; z < this.sizeZ; z++) {
|
|
77
|
+
for (let y = 0; y < this.sizeY; y++) {
|
|
78
|
+
for (let x = 0; x < this.sizeX; x++)
|
|
79
|
+
d[i++] = fn(x, y, z);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
this.version++;
|
|
83
|
+
this.markAllDirty();
|
|
84
|
+
for (const l of this.listeners)
|
|
85
|
+
l.reset?.();
|
|
86
|
+
}
|
|
87
|
+
chunkAt(x, y, z) {
|
|
88
|
+
if (!this.inBounds(x, y, z))
|
|
89
|
+
return -1;
|
|
90
|
+
const c = this.chunk;
|
|
91
|
+
return this.chunkIndex(Math.floor(x / c), Math.floor(y / c), Math.floor(z / c));
|
|
92
|
+
}
|
|
93
|
+
chunkIndex(cx, cy, cz) {
|
|
94
|
+
return cx + this.chunksX * (cy + this.chunksY * cz);
|
|
95
|
+
}
|
|
96
|
+
chunkCoords(chunk, out) {
|
|
97
|
+
const cx = chunk % this.chunksX;
|
|
98
|
+
const rest = (chunk - cx) / this.chunksX;
|
|
99
|
+
const cy = rest % this.chunksY;
|
|
100
|
+
out[0] = cx;
|
|
101
|
+
out[1] = cy;
|
|
102
|
+
out[2] = (rest - cy) / this.chunksY;
|
|
103
|
+
}
|
|
104
|
+
chunkEmpty(chunk) {
|
|
105
|
+
const c = this.chunk;
|
|
106
|
+
const cx = chunk % this.chunksX;
|
|
107
|
+
const rest = (chunk - cx) / this.chunksX;
|
|
108
|
+
const cy = rest % this.chunksY;
|
|
109
|
+
const cz = (rest - cy) / this.chunksY;
|
|
110
|
+
const x1 = Math.min(this.sizeX, (cx + 1) * c);
|
|
111
|
+
const y1 = Math.min(this.sizeY, (cy + 1) * c);
|
|
112
|
+
const z1 = Math.min(this.sizeZ, (cz + 1) * c);
|
|
113
|
+
const d = this.data;
|
|
114
|
+
for (let z = cz * c; z < z1; z++) {
|
|
115
|
+
for (let y = cy * c; y < y1; y++) {
|
|
116
|
+
const row = this.sizeX * (y + this.sizeY * z);
|
|
117
|
+
for (let x = cx * c; x < x1; x++)
|
|
118
|
+
if (d[row + x] !== 0)
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
isDirty(chunk) {
|
|
125
|
+
return this.dirty[chunk] === 1;
|
|
126
|
+
}
|
|
127
|
+
markDirty(chunk) {
|
|
128
|
+
if (chunk >= 0 && chunk < this.chunkCount)
|
|
129
|
+
this.dirty[chunk] = 1;
|
|
130
|
+
}
|
|
131
|
+
markAllDirty() {
|
|
132
|
+
this.dirty.fill(1);
|
|
133
|
+
}
|
|
134
|
+
clearDirty(chunk) {
|
|
135
|
+
if (chunk >= 0 && chunk < this.chunkCount)
|
|
136
|
+
this.dirty[chunk] = 0;
|
|
137
|
+
}
|
|
138
|
+
forEachDirtyChunk(fn) {
|
|
139
|
+
let n = 0;
|
|
140
|
+
const d = this.dirty;
|
|
141
|
+
for (let c = 0; c < d.length; c++) {
|
|
142
|
+
if (d[c] !== 1)
|
|
143
|
+
continue;
|
|
144
|
+
d[c] = 0;
|
|
145
|
+
n++;
|
|
146
|
+
fn(c);
|
|
147
|
+
}
|
|
148
|
+
return n;
|
|
149
|
+
}
|
|
150
|
+
serialize() {
|
|
151
|
+
const buffer = new ArrayBuffer(HEADER_BYTES + this.data.length);
|
|
152
|
+
const header = new Uint32Array(buffer, 0, 4);
|
|
153
|
+
header[0] = this.sizeX;
|
|
154
|
+
header[1] = this.sizeY;
|
|
155
|
+
header[2] = this.sizeZ;
|
|
156
|
+
header[3] = this.chunk;
|
|
157
|
+
new Uint8Array(buffer, HEADER_BYTES).set(this.data);
|
|
158
|
+
return buffer;
|
|
159
|
+
}
|
|
160
|
+
deserialize(buffer) {
|
|
161
|
+
const header = readHeader(buffer);
|
|
162
|
+
if (header.sizeX !== this.sizeX ||
|
|
163
|
+
header.sizeY !== this.sizeY ||
|
|
164
|
+
header.sizeZ !== this.sizeZ ||
|
|
165
|
+
header.chunk !== this.chunk) {
|
|
166
|
+
throw new Error('VoxelGrid.deserialize: the buffer holds a grid of other sizes');
|
|
167
|
+
}
|
|
168
|
+
this.data.set(new Uint8Array(buffer, HEADER_BYTES, this.data.length));
|
|
169
|
+
this.version++;
|
|
170
|
+
this.markAllDirty();
|
|
171
|
+
for (const l of this.listeners)
|
|
172
|
+
l.reset?.();
|
|
173
|
+
}
|
|
174
|
+
subscribe(listener) {
|
|
175
|
+
this.listeners.push(listener);
|
|
176
|
+
return () => {
|
|
177
|
+
const i = this.listeners.indexOf(listener);
|
|
178
|
+
if (i >= 0)
|
|
179
|
+
this.listeners.splice(i, 1);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/** Flag the chunk of (x, y, z) and every chunk within one cell of it. */
|
|
183
|
+
touch(x, y, z) {
|
|
184
|
+
const c = this.chunk;
|
|
185
|
+
const cx = Math.floor(x / c);
|
|
186
|
+
const cy = Math.floor(y / c);
|
|
187
|
+
const cz = Math.floor(z / c);
|
|
188
|
+
const x0 = x % c === 0 && cx > 0 ? cx - 1 : cx;
|
|
189
|
+
const x1 = x % c === c - 1 && cx + 1 < this.chunksX ? cx + 1 : cx;
|
|
190
|
+
const y0 = y % c === 0 && cy > 0 ? cy - 1 : cy;
|
|
191
|
+
const y1 = y % c === c - 1 && cy + 1 < this.chunksY ? cy + 1 : cy;
|
|
192
|
+
const z0 = z % c === 0 && cz > 0 ? cz - 1 : cz;
|
|
193
|
+
const z1 = z % c === c - 1 && cz + 1 < this.chunksZ ? cz + 1 : cz;
|
|
194
|
+
for (let k = z0; k <= z1; k++) {
|
|
195
|
+
for (let j = y0; j <= y1; j++) {
|
|
196
|
+
for (let i = x0; i <= x1; i++)
|
|
197
|
+
this.dirty[this.chunkIndex(i, j, k)] = 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function readHeader(buffer) {
|
|
203
|
+
if (buffer.byteLength < HEADER_BYTES)
|
|
204
|
+
throw new Error('voxel grid buffer: too short');
|
|
205
|
+
const h = new Uint32Array(buffer, 0, 4);
|
|
206
|
+
const opts = { sizeX: h[0], sizeY: h[1], sizeZ: h[2], chunk: h[3] };
|
|
207
|
+
if (buffer.byteLength !== HEADER_BYTES + opts.sizeX * opts.sizeY * opts.sizeZ) {
|
|
208
|
+
throw new Error('voxel grid buffer: length does not match its header');
|
|
209
|
+
}
|
|
210
|
+
return opts;
|
|
211
|
+
}
|
|
212
|
+
/** A grid of air. */
|
|
213
|
+
export function createVoxelGrid(opts) {
|
|
214
|
+
return new Grid(opts);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* A grid over the cells of a `serialize()` buffer: the grid reads and writes that buffer in
|
|
218
|
+
* place (no copy), so a Worker handed the transferred buffer owns the cells.
|
|
219
|
+
*/
|
|
220
|
+
export function deserializeVoxelGrid(buffer) {
|
|
221
|
+
const opts = readHeader(buffer);
|
|
222
|
+
return new Grid(opts, new Uint8Array(buffer, HEADER_BYTES));
|
|
223
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@thunderclap-engine/engine/voxel`: block grids into chunk meshes and onto the screen. A
|
|
3
|
+
* `VoxelGrid` of block ids with per-chunk dirty flags, a greedy mesher with baked ambient
|
|
4
|
+
* occlusion (`meshChunk`, pure, Worker-ready) and its Worker bridge (`createVoxelMesher`,
|
|
5
|
+
* `installVoxelMesherWorker`), a chunk renderer that owns one mesh per non-empty chunk and
|
|
6
|
+
* frustum-culls them (`createVoxelChunks`), a block-picking ray (`raycastVoxels`) and the WGSL
|
|
7
|
+
* prelude a block material reads the vertex convention with (`VOXEL_WGSL`). The game ships the
|
|
8
|
+
* blocks: what each id is, which texture layer each face shows, what a click does.
|
|
9
|
+
*/
|
|
10
|
+
export type { VoxelChunks, VoxelChunksOptions, VoxelChunksStats, VoxelDrawStats, } from './chunks.js';
|
|
11
|
+
export { createVoxelChunks } from './chunks.js';
|
|
12
|
+
export type { VoxelGrid, VoxelGridListener, VoxelGridOptions } from './grid.js';
|
|
13
|
+
export { createVoxelGrid, deserializeVoxelGrid } from './grid.js';
|
|
14
|
+
export type { ChunkMeshOut, MeshChunkOptions, VoxelFace } from './mesher.js';
|
|
15
|
+
export { countExposedFaces, createChunkMeshOut, meshChunk, VOXEL_AO_CURVE, VOXEL_FACE_NORMALS, VOXEL_VERTEX_FLOATS, } from './mesher.js';
|
|
16
|
+
export type { VoxelWorkerScopeLike } from './mesher-worker.js';
|
|
17
|
+
export { installVoxelMesherWorker } from './mesher-worker.js';
|
|
18
|
+
export type { VoxelHit } from './ray.js';
|
|
19
|
+
export { createVoxelHit, raycastVoxels } from './ray.js';
|
|
20
|
+
export { VOXEL_WGSL } from './wgsl.js';
|
|
21
|
+
export type { ChunkMesh, VoxelMesher, VoxelMesherOptions, VoxelMesherReply, VoxelMesherRequest, VoxelWorkerLike, } from './worker-client.js';
|
|
22
|
+
export { createVoxelMesher, packChunkMesh } from './worker-client.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createVoxelChunks } from './chunks.js';
|
|
2
|
+
export { createVoxelGrid, deserializeVoxelGrid } from './grid.js';
|
|
3
|
+
export { countExposedFaces, createChunkMeshOut, meshChunk, VOXEL_AO_CURVE, VOXEL_FACE_NORMALS, VOXEL_VERTEX_FLOATS, } from './mesher.js';
|
|
4
|
+
export { installVoxelMesherWorker } from './mesher-worker.js';
|
|
5
|
+
export { createVoxelHit, raycastVoxels } from './ray.js';
|
|
6
|
+
export { VOXEL_WGSL } from './wgsl.js';
|
|
7
|
+
export { createVoxelMesher, packChunkMesh } from './worker-client.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type MeshChunkOptions } from './mesher.js';
|
|
2
|
+
import { type VoxelMesherReply, type VoxelMesherRequest } from './worker-client.js';
|
|
3
|
+
/** The part of a Worker's global scope the install uses (a test passes a fake). */
|
|
4
|
+
export interface VoxelWorkerScopeLike {
|
|
5
|
+
postMessage(message: VoxelMesherReply, transfer?: Transferable[]): void;
|
|
6
|
+
addEventListener(type: 'message', listener: (e: {
|
|
7
|
+
data: unknown;
|
|
8
|
+
}) => void): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Listen for `VoxelMesherRequest`s on `scope` (default the Worker's `self`) and answer `mesh`
|
|
12
|
+
* requests. Returns the handler, so a test can call it directly.
|
|
13
|
+
*/
|
|
14
|
+
export declare function installVoxelMesherWorker(opts?: MeshChunkOptions, scope?: VoxelWorkerScopeLike): (req: VoxelMesherRequest) => void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Worker side of `createVoxelMesher`. A game's worker script is two lines: import
|
|
3
|
+
* `installVoxelMesherWorker` from the voxel subpath and call it with the mesher options
|
|
4
|
+
* (`installVoxelMesherWorker({ layerOf })`); the page makes `new Worker(new URL('./mesher.worker.ts', import.meta.url), { type: 'module' })`
|
|
5
|
+
* and hands it to `createVoxelMesher(grid, { worker })`. The Worker keeps its own `VoxelGrid`
|
|
6
|
+
* over the buffer the client transfers, applies the edits the client mirrors and answers each
|
|
7
|
+
* `mesh` request with one transferred `ChunkMesh` buffer. `opts` are the mesher's
|
|
8
|
+
* (`layerOf`, `ao`, `outside`...): functions cannot cross the thread boundary, so the game
|
|
9
|
+
* names them here and again on the client for its in-thread fallback.
|
|
10
|
+
*/
|
|
11
|
+
import { deserializeVoxelGrid } from './grid.js';
|
|
12
|
+
import { createChunkMeshOut, meshChunk } from './mesher.js';
|
|
13
|
+
import { packChunkMesh } from './worker-client.js';
|
|
14
|
+
const coords = [0, 0, 0];
|
|
15
|
+
/**
|
|
16
|
+
* Listen for `VoxelMesherRequest`s on `scope` (default the Worker's `self`) and answer `mesh`
|
|
17
|
+
* requests. Returns the handler, so a test can call it directly.
|
|
18
|
+
*/
|
|
19
|
+
export function installVoxelMesherWorker(opts = {}, scope = self) {
|
|
20
|
+
let grid = null;
|
|
21
|
+
let out = null;
|
|
22
|
+
const handle = (req) => {
|
|
23
|
+
if (req.type === 'grid') {
|
|
24
|
+
grid = deserializeVoxelGrid(req.buffer);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!grid)
|
|
28
|
+
return;
|
|
29
|
+
if (req.type === 'set') {
|
|
30
|
+
grid.set(req.x, req.y, req.z, req.block);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (req.type === 'mesh') {
|
|
34
|
+
out ??= createChunkMeshOut();
|
|
35
|
+
grid.chunkCoords(req.chunk, coords);
|
|
36
|
+
meshChunk(grid, coords[0], coords[1], coords[2], opts, out);
|
|
37
|
+
const reply = { type: 'mesh', ...packChunkMesh(out, req.chunk) };
|
|
38
|
+
scope.postMessage(reply, [reply.buffer]);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
scope.addEventListener('message', (e) => {
|
|
42
|
+
const req = e.data;
|
|
43
|
+
if (req && typeof req === 'object' && 'type' in req)
|
|
44
|
+
handle(req);
|
|
45
|
+
});
|
|
46
|
+
return handle;
|
|
47
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The chunk mesher: a block grid in, greedy-merged quads out, in `VERTEX_LAYOUT_3D` (12 floats:
|
|
3
|
+
* position, normal, uv, rgba) with uint32 indices. Pure arithmetic over a `VoxelGrid`, so it
|
|
4
|
+
* runs the same on the main thread or in a Worker (`mesher-worker.ts`).
|
|
5
|
+
*
|
|
6
|
+
* Convention (the block material's contract, see README):
|
|
7
|
+
* - positions are chunk-local block units (0..chunk on each axis); the renderer places each
|
|
8
|
+
* chunk by a transform at its origin;
|
|
9
|
+
* - the normal is the face's axis;
|
|
10
|
+
* - uv is in block units across the quad, u along the face's right, v downward from the top
|
|
11
|
+
* of the quad (a texture's row 0 is its top), so a merged 3×2 quad spans uv 0..3 × 0..2 and
|
|
12
|
+
* the material wraps it (`voxel_uv_wrap` or a `repeat` sampler);
|
|
13
|
+
* - colour rgb is the baked ambient occlusion (`aoCurve` of the corner's level, 1 = open) and
|
|
14
|
+
* colour a is the texture-array layer from `layerOf(block, face)`.
|
|
15
|
+
*
|
|
16
|
+
* Greedy meshing: for each of the six face directions and each slice of the chunk along that
|
|
17
|
+
* axis, a `chunk × chunk` mask holds a key per exposed face (the layer and the four corner AO
|
|
18
|
+
* levels); runs of equal keys merge into one quad, first along the row, then down the rows.
|
|
19
|
+
* AO is the four-neighbour rule: each quad corner looks at the two side cells and the diagonal
|
|
20
|
+
* cell touching it on the face's outer side; both sides solid is the darkest level (0), else
|
|
21
|
+
* `3 - solid count`. A quad whose opposite corners differ in AO is split along the diagonal
|
|
22
|
+
* with the lower sum, so the dark pair shares an edge and the interpolation has no crease
|
|
23
|
+
* (the "riser triangle" a fixed diagonal shows on a one-block step).
|
|
24
|
+
*/
|
|
25
|
+
import type { MeshBounds } from '../render/mesh.js';
|
|
26
|
+
import type { VoxelGrid } from './grid.js';
|
|
27
|
+
/** A block face: 0 +x, 1 -x, 2 +y, 3 -y, 4 +z, 5 -z. */
|
|
28
|
+
export type VoxelFace = 0 | 1 | 2 | 3 | 4 | 5;
|
|
29
|
+
/** Outward normal of each `VoxelFace`. */
|
|
30
|
+
export declare const VOXEL_FACE_NORMALS: readonly (readonly [number, number, number])[];
|
|
31
|
+
/** Default AO curve: corner level (0 darkest .. 3 open) → vertex brightness. */
|
|
32
|
+
export declare const VOXEL_AO_CURVE: readonly number[];
|
|
33
|
+
/** Floats per vertex of the mesher's output (`VERTEX_LAYOUT_3D`). */
|
|
34
|
+
export declare const VOXEL_VERTEX_FLOATS = 12;
|
|
35
|
+
export interface MeshChunkOptions {
|
|
36
|
+
/** Bake ambient occlusion into colour.rgb. Default true (off: rgb = 1, more merging). */
|
|
37
|
+
ao?: boolean;
|
|
38
|
+
/** Brightness per AO level, 4 entries. Default `VOXEL_AO_CURVE`. */
|
|
39
|
+
aoCurve?: ArrayLike<number>;
|
|
40
|
+
/** Texture-array layer of a block's face, written to colour.a. Default `block - 1`. */
|
|
41
|
+
layerOf?: (block: number, face: VoxelFace) => number;
|
|
42
|
+
/**
|
|
43
|
+
* What lies beyond the grid: a block id for every outside cell (0 = air, so the grid's
|
|
44
|
+
* boundary faces show), or a function of the cell (solid below y 0 and air elsewhere hides
|
|
45
|
+
* a world's underside). Default 0.
|
|
46
|
+
*/
|
|
47
|
+
outside?: number | ((x: number, y: number, z: number) => number);
|
|
48
|
+
}
|
|
49
|
+
/** The mesher's output buffers, reused across calls and grown with slack when a chunk needs more. */
|
|
50
|
+
export interface ChunkMeshOut {
|
|
51
|
+
vertices: Float32Array;
|
|
52
|
+
indices: Uint32Array;
|
|
53
|
+
/** Vertices written by the last `meshChunk` (`vertexCount * VOXEL_VERTEX_FLOATS` floats). */
|
|
54
|
+
vertexCount: number;
|
|
55
|
+
/** Indices written by the last `meshChunk` (6 per quad). */
|
|
56
|
+
indexCount: number;
|
|
57
|
+
/** Bounding sphere of the last output in chunk-local units; radius 0 when empty. */
|
|
58
|
+
bounds: MeshBounds;
|
|
59
|
+
}
|
|
60
|
+
/** Output buffers with room for `quads` quads before the first growth. */
|
|
61
|
+
export declare function createChunkMeshOut(quads?: number): ChunkMeshOut;
|
|
62
|
+
/**
|
|
63
|
+
* Mesh chunk (`cx`, `cy`, `cz`) of `grid` into `out`. Returns `out`. Every quad is planar on
|
|
64
|
+
* its face's axis, winds counter-clockwise seen from outside (both triangles) and its vertex
|
|
65
|
+
* normal is the face's normal. `out.vertexCount` 0 means an empty chunk.
|
|
66
|
+
*/
|
|
67
|
+
export declare function meshChunk(grid: VoxelGrid, cx: number, cy: number, cz: number, opts: MeshChunkOptions, out: ChunkMeshOut): ChunkMeshOut;
|
|
68
|
+
/**
|
|
69
|
+
* Exposed faces of chunk (`cx`, `cy`, `cz`) counted one cell at a time (no merging): the
|
|
70
|
+
* reference the mesher's quads must cover exactly. Each quad of `meshChunk` covers
|
|
71
|
+
* `w × h` of these, so a test sums quad areas against it. Same `outside` rule.
|
|
72
|
+
*/
|
|
73
|
+
export declare function countExposedFaces(grid: VoxelGrid, cx: number, cy: number, cz: number, outside?: MeshChunkOptions['outside']): number;
|