@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,208 @@
|
|
|
1
|
+
import { mat4 } from '../core/math.js';
|
|
2
|
+
import { Camera } from './camera.js';
|
|
3
|
+
import { DEFAULT_SHADOW_BIAS } from './lights.js';
|
|
4
|
+
import { INSTANCE_BUFFER_LAYOUT } from './material.js';
|
|
5
|
+
import { createShaderModule, materialPrelude } from './wgsl.js';
|
|
6
|
+
/** Depth format of the sun's shadow map (and of the 1×1 placeholder bound without one). */
|
|
7
|
+
export const SHADOW_FORMAT = 'depth32float';
|
|
8
|
+
/** Shadow map side in texels when `SunShadow.size` is not given. */
|
|
9
|
+
export const DEFAULT_SHADOW_SIZE = 2048;
|
|
10
|
+
const UP = new Float32Array([0, 1, 0]);
|
|
11
|
+
const UP_Z = new Float32Array([0, 0, 1]);
|
|
12
|
+
/**
|
|
13
|
+
* The sun's shadow map: one `depth32float` texture, a comparison sampler, a 1×1 placeholder
|
|
14
|
+
* depth texture (what every view binds at `@group(0) @binding(3)` until a shadow pass has
|
|
15
|
+
* rendered) and a depth-only pipeline per vertex layout. The renderer owns one and, for each
|
|
16
|
+
* `render` whose `frame.lights.sun.shadow` is set, encodes a shadow pass through `sunCamera`
|
|
17
|
+
* (an orthographic `Camera` placed by `place`) over the view's opaque shadow-casting draws. A
|
|
18
|
+
* caster whose material has a `shadowFragmentEntry` (alpha mask, dissolve) draws through that
|
|
19
|
+
* material's `shadowPipelineFor` instead, so its holes show in the shadow.
|
|
20
|
+
* Engine-internal; games set `Lights.sun.shadow`.
|
|
21
|
+
*/
|
|
22
|
+
export class ShadowMap {
|
|
23
|
+
/** Comparison sampler (`less-equal`: a receiver at or in front of the stored depth is lit). */
|
|
24
|
+
sampler;
|
|
25
|
+
/** 1×1 depth view bound in place of the map (and in the shadow pass itself). */
|
|
26
|
+
placeholder;
|
|
27
|
+
/** The orthographic camera the shadow pass renders through; `place` sets it. */
|
|
28
|
+
sunCamera = new Camera();
|
|
29
|
+
/** What `Lights.writeBlock` needs for the view this map was rendered for. */
|
|
30
|
+
uniforms;
|
|
31
|
+
/** Side of the current map in texels, 0 before the first shadow pass. */
|
|
32
|
+
size = 0;
|
|
33
|
+
/** Bumped every time the map texture is (re)created, so bind groups can follow it. */
|
|
34
|
+
generation = 0;
|
|
35
|
+
texture = null;
|
|
36
|
+
/** Maps replaced this frame (passes already encoded may still read them); see `flush`. */
|
|
37
|
+
retired = [];
|
|
38
|
+
mapView;
|
|
39
|
+
placeholderTex;
|
|
40
|
+
device;
|
|
41
|
+
pipelineLayout;
|
|
42
|
+
pipelines = new Map();
|
|
43
|
+
/** Skinned layouts: one pipeline per material bind group layout (the palette is group 1). */
|
|
44
|
+
skinnedPipelines = new Map();
|
|
45
|
+
globalsLayout;
|
|
46
|
+
viewM = mat4.create();
|
|
47
|
+
projM = mat4.create();
|
|
48
|
+
eye = new Float32Array(3);
|
|
49
|
+
target = new Float32Array(3);
|
|
50
|
+
depthAtt;
|
|
51
|
+
/** The shadow pass descriptor; its attachment view follows `view`. */
|
|
52
|
+
passDesc;
|
|
53
|
+
constructor(device, globalsLayout) {
|
|
54
|
+
this.device = device;
|
|
55
|
+
this.globalsLayout = globalsLayout;
|
|
56
|
+
this.sampler = device.createSampler({
|
|
57
|
+
label: 'engine-shadow-sampler',
|
|
58
|
+
compare: 'less-equal',
|
|
59
|
+
magFilter: 'linear',
|
|
60
|
+
minFilter: 'linear',
|
|
61
|
+
addressModeU: 'clamp-to-edge',
|
|
62
|
+
addressModeV: 'clamp-to-edge',
|
|
63
|
+
});
|
|
64
|
+
this.placeholderTex = device.createTexture({
|
|
65
|
+
label: 'engine-shadow-placeholder',
|
|
66
|
+
size: [1, 1],
|
|
67
|
+
format: SHADOW_FORMAT,
|
|
68
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
69
|
+
});
|
|
70
|
+
this.placeholder = this.placeholderTex.createView({ label: 'engine-shadow-placeholder' });
|
|
71
|
+
this.mapView = this.placeholder;
|
|
72
|
+
this.pipelineLayout = device.createPipelineLayout({
|
|
73
|
+
label: 'engine-shadow-layout',
|
|
74
|
+
bindGroupLayouts: [globalsLayout],
|
|
75
|
+
});
|
|
76
|
+
this.depthAtt = {
|
|
77
|
+
view: this.placeholder,
|
|
78
|
+
depthClearValue: 1,
|
|
79
|
+
depthLoadOp: 'clear',
|
|
80
|
+
depthStoreOp: 'store',
|
|
81
|
+
};
|
|
82
|
+
this.passDesc = {
|
|
83
|
+
label: 'shadow',
|
|
84
|
+
colorAttachments: [],
|
|
85
|
+
depthStencilAttachment: this.depthAtt,
|
|
86
|
+
};
|
|
87
|
+
this.uniforms = { viewProj: this.sunCamera.viewProjection, bias: 0, texelSize: 0 };
|
|
88
|
+
this.sunCamera.depthTest = true;
|
|
89
|
+
this.sunCamera.depthWrite = true;
|
|
90
|
+
}
|
|
91
|
+
/** The map's view when one has been rendered, else `placeholder`. */
|
|
92
|
+
get view() {
|
|
93
|
+
return this.mapView;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Make sure the map is `size` texels square (creating or replacing the texture; bumps
|
|
97
|
+
* `generation` when it does). Returns whether the texture changed.
|
|
98
|
+
*/
|
|
99
|
+
ensure(size) {
|
|
100
|
+
if (this.texture && this.size === size)
|
|
101
|
+
return false;
|
|
102
|
+
if (this.texture)
|
|
103
|
+
this.retired.push(this.texture);
|
|
104
|
+
this.texture = this.device.createTexture({
|
|
105
|
+
label: 'engine-shadow-map',
|
|
106
|
+
size: [size, size],
|
|
107
|
+
format: SHADOW_FORMAT,
|
|
108
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
109
|
+
});
|
|
110
|
+
this.mapView = this.texture.createView({ label: 'engine-shadow-map' });
|
|
111
|
+
this.depthAtt.view = this.mapView;
|
|
112
|
+
this.size = size;
|
|
113
|
+
this.generation++;
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Point `sunCamera` along `sunDir` through an orthographic box centred on `center` (the
|
|
118
|
+
* rendering camera's position): half-width `shadow.extent`, depth `near..far` along the
|
|
119
|
+
* light measured from `center` (defaults `-extent..extent`). Fills `uniforms` for a map of
|
|
120
|
+
* `size` texels. No allocation.
|
|
121
|
+
*/
|
|
122
|
+
place(center, sunDir, shadow, size) {
|
|
123
|
+
const dx = sunDir[0] ?? 0;
|
|
124
|
+
const dy = sunDir[1] ?? 0;
|
|
125
|
+
const dz = sunDir[2] ?? 0;
|
|
126
|
+
const len = Math.hypot(dx, dy, dz) || 1;
|
|
127
|
+
const e = this.eye;
|
|
128
|
+
const t = this.target;
|
|
129
|
+
e[0] = center[0] ?? 0;
|
|
130
|
+
e[1] = center[1] ?? 0;
|
|
131
|
+
e[2] = center[2] ?? 0;
|
|
132
|
+
t[0] = e[0] + dx / len;
|
|
133
|
+
t[1] = e[1] + dy / len;
|
|
134
|
+
t[2] = e[2] + dz / len;
|
|
135
|
+
// A sun straight up or down has no stable +y "up"; use +z then.
|
|
136
|
+
const up = Math.abs(dy / len) > 0.999 ? UP_Z : UP;
|
|
137
|
+
mat4.lookAt(this.viewM, e, t, up);
|
|
138
|
+
const extent = shadow.extent;
|
|
139
|
+
const near = shadow.near ?? -extent;
|
|
140
|
+
const far = shadow.far ?? extent;
|
|
141
|
+
mat4.ortho(this.projM, -extent, extent, -extent, extent, near, far);
|
|
142
|
+
this.sunCamera.setView(this.viewM);
|
|
143
|
+
this.sunCamera.setProjection(this.projM);
|
|
144
|
+
const u = this.uniforms;
|
|
145
|
+
u.viewProj = this.sunCamera.viewProjection;
|
|
146
|
+
u.bias = shadow.bias ?? DEFAULT_SHADOW_BIAS;
|
|
147
|
+
u.texelSize = 1 / size;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The depth-only pipeline for meshes in `layout`: the engine prelude's `vs_main` (so the same
|
|
151
|
+
* `engine_vertex` path as the scene pass), no fragment stage, `SHADOW_FORMAT` depth with
|
|
152
|
+
* writes on. Built on first use and cached. A skinned layout with `bindingsLayout` (the
|
|
153
|
+
* material's group 1, which holds the joint palette) gets a pipeline layout of both groups.
|
|
154
|
+
*/
|
|
155
|
+
pipelineFor(layout, bindingsLayout) {
|
|
156
|
+
const skinned = layout.skinned === true && bindingsLayout !== undefined;
|
|
157
|
+
let byGroup;
|
|
158
|
+
if (skinned) {
|
|
159
|
+
byGroup = this.skinnedPipelines.get(layout);
|
|
160
|
+
if (!byGroup) {
|
|
161
|
+
byGroup = new Map();
|
|
162
|
+
this.skinnedPipelines.set(layout, byGroup);
|
|
163
|
+
}
|
|
164
|
+
const hit = byGroup.get(bindingsLayout);
|
|
165
|
+
if (hit)
|
|
166
|
+
return hit;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const hit = this.pipelines.get(layout);
|
|
170
|
+
if (hit)
|
|
171
|
+
return hit;
|
|
172
|
+
}
|
|
173
|
+
const module = createShaderModule(this.device, materialPrelude(layout), `engine-shadow:${layout.name}`);
|
|
174
|
+
const pipeline = this.device.createRenderPipeline({
|
|
175
|
+
label: `engine-shadow:${layout.name}`,
|
|
176
|
+
layout: skinned
|
|
177
|
+
? this.device.createPipelineLayout({
|
|
178
|
+
label: `engine-shadow-layout:${layout.name}`,
|
|
179
|
+
bindGroupLayouts: [this.globalsLayout, bindingsLayout],
|
|
180
|
+
})
|
|
181
|
+
: this.pipelineLayout,
|
|
182
|
+
vertex: { module, entryPoint: 'vs_main', buffers: [layout.buffer, INSTANCE_BUFFER_LAYOUT] },
|
|
183
|
+
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
184
|
+
depthStencil: { format: SHADOW_FORMAT, depthWriteEnabled: true, depthCompare: 'less' },
|
|
185
|
+
});
|
|
186
|
+
if (byGroup)
|
|
187
|
+
byGroup.set(bindingsLayout, pipeline);
|
|
188
|
+
else
|
|
189
|
+
this.pipelines.set(layout, pipeline);
|
|
190
|
+
return pipeline;
|
|
191
|
+
}
|
|
192
|
+
/** Destroy maps replaced since the last call; the renderer calls it after each submit. */
|
|
193
|
+
flush() {
|
|
194
|
+
if (this.retired.length === 0)
|
|
195
|
+
return;
|
|
196
|
+
for (const t of this.retired)
|
|
197
|
+
t.destroy();
|
|
198
|
+
this.retired.length = 0;
|
|
199
|
+
}
|
|
200
|
+
destroy() {
|
|
201
|
+
this.flush();
|
|
202
|
+
this.texture?.destroy();
|
|
203
|
+
this.texture = null;
|
|
204
|
+
this.placeholderTex.destroy();
|
|
205
|
+
this.pipelines.clear();
|
|
206
|
+
this.skinnedPipelines.clear();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { InstanceParams } from './frame.js';
|
|
2
|
+
/**
|
|
3
|
+
* GPU skinning: a `SkinPalette` is the storage buffer of joint matrices that a material
|
|
4
|
+
* drawing `VERTEX_LAYOUT_SKINNED` meshes reads (`WGSL_SKIN` / `engine_skin` in the prelude).
|
|
5
|
+
*
|
|
6
|
+
* - One joint matrix is 12 floats (`JOINT_FLOATS`): a 3×4 row-major affine matrix, rows
|
|
7
|
+
* `r0 r1 r2` of four floats, the same layout as the instance matrix and as `anim`'s
|
|
8
|
+
* `skinMatrices` output (world × inverse bind, per joint).
|
|
9
|
+
* - The palette holds `instances × joints` of them, instance after instance, after a 16-byte
|
|
10
|
+
* header (`joints`, `instances`) the shader reads to find an instance's block.
|
|
11
|
+
* - A draw names its block with the palette slot in `InstanceParams.params[3]` (`params.w`,
|
|
12
|
+
* read as `u32`); the other three `params` stay the material's. Several draws may share one
|
|
13
|
+
* slot.
|
|
14
|
+
* - `set(slot, matrices)` copies one instance's matrices into CPU staging and marks it dirty;
|
|
15
|
+
* `flush()` uploads the dirty range in one `writeBuffer`, once per frame, allocating nothing.
|
|
16
|
+
*
|
|
17
|
+
* Bind it to a material with `buffers: [palette.buffer]` (`BindingDesc.buffers`, binding 16).
|
|
18
|
+
* A palette is one material's; two skinned materials take two palettes, or one shared buffer
|
|
19
|
+
* passed to both.
|
|
20
|
+
*/
|
|
21
|
+
export interface SkinPaletteDesc {
|
|
22
|
+
/** Joints per instance (the skeleton's joint count). */
|
|
23
|
+
joints: number;
|
|
24
|
+
/** Instances (palette slots) the buffer holds. Default 1. */
|
|
25
|
+
instances?: number;
|
|
26
|
+
label?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Keep last frame's matrices too (ws/render-4): the buffer holds `[header][current]
|
|
29
|
+
* [previous]` and the prelude's `engine_skin_previous` reads the previous block, so a
|
|
30
|
+
* skinned draw into a target with a velocity attachment writes its own motion. `flush()`
|
|
31
|
+
* settles it: a slot set this frame keeps what it held before as "previous"; one left alone
|
|
32
|
+
* reads the same matrices both frames (zero motion). Default false (velocity reads zero).
|
|
33
|
+
*/
|
|
34
|
+
history?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Floats in one joint matrix: 3 rows × 4 (row-major 3×4 affine). */
|
|
37
|
+
export declare const JOINT_FLOATS = 12;
|
|
38
|
+
/** Floats of the palette header before the first joint row (`joints`, `instances`, `history`, pad). */
|
|
39
|
+
export declare const SKIN_PALETTE_HEADER_FLOATS = 4;
|
|
40
|
+
export declare class SkinPalette {
|
|
41
|
+
private readonly device;
|
|
42
|
+
readonly label: string;
|
|
43
|
+
readonly joints: number;
|
|
44
|
+
readonly instances: number;
|
|
45
|
+
/** The storage buffer (`STORAGE | COPY_DST`), sized at creation; bind it as `buffers[0]`. */
|
|
46
|
+
readonly buffer: GPUBuffer;
|
|
47
|
+
/** Floats per instance block (`joints × JOINT_FLOATS`). */
|
|
48
|
+
readonly instanceFloats: number;
|
|
49
|
+
/** `SkinPaletteDesc.history`: the buffer carries last frame's matrices after the current. */
|
|
50
|
+
readonly history: boolean;
|
|
51
|
+
private readonly data;
|
|
52
|
+
/** Dirty instance range, inclusive; `lo > hi` means clean. */
|
|
53
|
+
private dirtyLo;
|
|
54
|
+
private dirtyHi;
|
|
55
|
+
/** With history: the flush each slot was last written in (0 = never); `flushes` counts them. */
|
|
56
|
+
private readonly stamp;
|
|
57
|
+
private flushes;
|
|
58
|
+
/** `write(i)` views, made on first use. */
|
|
59
|
+
private views;
|
|
60
|
+
/** `params(i)` objects, made on first use. */
|
|
61
|
+
private slotParams;
|
|
62
|
+
/** With history: slots whose previous block must follow their current one at the next flush. */
|
|
63
|
+
private settleLo;
|
|
64
|
+
private settleHi;
|
|
65
|
+
constructor(device: GPUDevice, desc: SkinPaletteDesc);
|
|
66
|
+
/**
|
|
67
|
+
* Joints per instance (ws/render-11): `joints`, the count each slot's block holds and the
|
|
68
|
+
* most a skeleton posed into it (`skinPose`, `skinMatrices`) may have.
|
|
69
|
+
*/
|
|
70
|
+
get jointCount(): number;
|
|
71
|
+
/** Float offset of `instance`'s first joint row inside the buffer (tests, custom writers). */
|
|
72
|
+
offsetOf(instance: number): number;
|
|
73
|
+
/** Float offset of `instance`'s previous-frame block (`history` palettes only; else -1). */
|
|
74
|
+
previousOffsetOf(instance: number): number;
|
|
75
|
+
/**
|
|
76
|
+
* Copy `joints × 12` floats from `matrices` (starting at float `offset`) into palette slot
|
|
77
|
+
* `instance`. The upload happens in `flush()`. No allocation.
|
|
78
|
+
*/
|
|
79
|
+
set(instance: number, matrices: ArrayLike<number>, offset?: number): void;
|
|
80
|
+
/**
|
|
81
|
+
* Slot `instance`'s `joints × 12` floats to write in place (ws/api-render), for example
|
|
82
|
+
* `skinMatrices(skeleton, world, palette.write(0))` with no staging array of your own. Marks
|
|
83
|
+
* the slot for the next `flush()` (and, with `history`, keeps its current block as the
|
|
84
|
+
* previous one first), so call it each frame you write the slot, before writing. The view is
|
|
85
|
+
* made once per slot; no allocation after that.
|
|
86
|
+
*/
|
|
87
|
+
write(instance: number): Float32Array<ArrayBuffer>;
|
|
88
|
+
/**
|
|
89
|
+
* The `InstanceParams` that draw with slot `instance` (ws/api-render): `params` is
|
|
90
|
+
* `[0, 0, 0, instance]`, the slot in `params[SKIN_PARAM]`. One object per slot, made on first
|
|
91
|
+
* use; pass it to `frame.mesh(mesh, material, transform, palette.params(i))`.
|
|
92
|
+
*/
|
|
93
|
+
params(instance: number): InstanceParams;
|
|
94
|
+
/** Reset every joint of slot `instance` to the identity (the mesh's bind pose). */
|
|
95
|
+
setIdentity(instance: number): void;
|
|
96
|
+
/** Upload the slots written since the last flush in one `writeBuffer`; nothing when clean. */
|
|
97
|
+
flush(): void;
|
|
98
|
+
/** With history: the first write to a slot in a frame keeps its current block as previous. */
|
|
99
|
+
private capture;
|
|
100
|
+
/** True when a `flush()` would upload something. */
|
|
101
|
+
get isDirty(): boolean;
|
|
102
|
+
destroy(): void;
|
|
103
|
+
private check;
|
|
104
|
+
private dirty;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Write the joints and weights of vertex `vertex` of a `VERTEX_LAYOUT_SKINNED` buffer, through
|
|
108
|
+
* `bytes`, a `Uint8Array` over the vertex data (`new Uint8Array(vertices.buffer)`). Weights are
|
|
109
|
+
* normalised to sum to 1 and quantised to unorm8 so the four bytes add up to 255. Up to four
|
|
110
|
+
* joints; missing entries read joint 0 with weight 0.
|
|
111
|
+
*/
|
|
112
|
+
export declare function setVertexSkin(bytes: Uint8Array, vertex: number, joints: ArrayLike<number>, weights: ArrayLike<number>): void;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { SKIN_JOINTS_BYTE_OFFSET, SKIN_WEIGHTS_BYTE_OFFSET, VERTEX_SKINNED_STRIDE } from './mesh.js';
|
|
2
|
+
/** Floats in one joint matrix: 3 rows × 4 (row-major 3×4 affine). */
|
|
3
|
+
export const JOINT_FLOATS = 12;
|
|
4
|
+
/** Floats of the palette header before the first joint row (`joints`, `instances`, `history`, pad). */
|
|
5
|
+
export const SKIN_PALETTE_HEADER_FLOATS = 4;
|
|
6
|
+
export class SkinPalette {
|
|
7
|
+
device;
|
|
8
|
+
label;
|
|
9
|
+
joints;
|
|
10
|
+
instances;
|
|
11
|
+
/** The storage buffer (`STORAGE | COPY_DST`), sized at creation; bind it as `buffers[0]`. */
|
|
12
|
+
buffer;
|
|
13
|
+
/** Floats per instance block (`joints × JOINT_FLOATS`). */
|
|
14
|
+
instanceFloats;
|
|
15
|
+
/** `SkinPaletteDesc.history`: the buffer carries last frame's matrices after the current. */
|
|
16
|
+
history;
|
|
17
|
+
data;
|
|
18
|
+
/** Dirty instance range, inclusive; `lo > hi` means clean. */
|
|
19
|
+
dirtyLo = 0;
|
|
20
|
+
dirtyHi = -1;
|
|
21
|
+
/** With history: the flush each slot was last written in (0 = never); `flushes` counts them. */
|
|
22
|
+
stamp;
|
|
23
|
+
flushes = 1;
|
|
24
|
+
/** `write(i)` views, made on first use. */
|
|
25
|
+
views = [];
|
|
26
|
+
/** `params(i)` objects, made on first use. */
|
|
27
|
+
slotParams = [];
|
|
28
|
+
/** With history: slots whose previous block must follow their current one at the next flush. */
|
|
29
|
+
settleLo = 0;
|
|
30
|
+
settleHi = -1;
|
|
31
|
+
constructor(device, desc) {
|
|
32
|
+
this.device = device;
|
|
33
|
+
const joints = Math.floor(desc.joints);
|
|
34
|
+
const instances = Math.floor(desc.instances ?? 1);
|
|
35
|
+
if (!(joints >= 1))
|
|
36
|
+
throw new Error(`SkinPalette: joints must be ≥ 1, got ${desc.joints}`);
|
|
37
|
+
if (!(instances >= 1)) {
|
|
38
|
+
throw new Error(`SkinPalette: instances must be ≥ 1, got ${desc.instances}`);
|
|
39
|
+
}
|
|
40
|
+
this.label = desc.label ?? 'skin-palette';
|
|
41
|
+
this.joints = joints;
|
|
42
|
+
this.instances = instances;
|
|
43
|
+
this.instanceFloats = joints * JOINT_FLOATS;
|
|
44
|
+
this.history = desc.history === true;
|
|
45
|
+
const blocks = this.history ? 2 : 1;
|
|
46
|
+
this.data = new Float32Array(SKIN_PALETTE_HEADER_FLOATS + blocks * instances * this.instanceFloats);
|
|
47
|
+
this.stamp = new Uint32Array(this.history ? instances : 0);
|
|
48
|
+
const header = new Uint32Array(this.data.buffer, 0, SKIN_PALETTE_HEADER_FLOATS);
|
|
49
|
+
header[0] = joints;
|
|
50
|
+
header[1] = instances;
|
|
51
|
+
header[2] = this.history ? 1 : 0;
|
|
52
|
+
this.buffer = device.createBuffer({
|
|
53
|
+
label: `${this.label}-buffer`,
|
|
54
|
+
size: this.data.byteLength,
|
|
55
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
56
|
+
});
|
|
57
|
+
// Identity everywhere, so an unset slot draws the mesh in its bind pose.
|
|
58
|
+
for (let i = 0; i < instances; i++)
|
|
59
|
+
this.setIdentity(i);
|
|
60
|
+
if (this.history) {
|
|
61
|
+
const n = instances * this.instanceFloats;
|
|
62
|
+
this.data.copyWithin(SKIN_PALETTE_HEADER_FLOATS + n, SKIN_PALETTE_HEADER_FLOATS, SKIN_PALETTE_HEADER_FLOATS + n);
|
|
63
|
+
}
|
|
64
|
+
// The header goes up with the first flush (the whole buffer is dirty).
|
|
65
|
+
this.device.queue.writeBuffer(this.buffer, 0, this.data.buffer, 0, SKIN_PALETTE_HEADER_FLOATS * 4);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Joints per instance (ws/render-11): `joints`, the count each slot's block holds and the
|
|
69
|
+
* most a skeleton posed into it (`skinPose`, `skinMatrices`) may have.
|
|
70
|
+
*/
|
|
71
|
+
get jointCount() {
|
|
72
|
+
return this.joints;
|
|
73
|
+
}
|
|
74
|
+
/** Float offset of `instance`'s first joint row inside the buffer (tests, custom writers). */
|
|
75
|
+
offsetOf(instance) {
|
|
76
|
+
return SKIN_PALETTE_HEADER_FLOATS + instance * this.instanceFloats;
|
|
77
|
+
}
|
|
78
|
+
/** Float offset of `instance`'s previous-frame block (`history` palettes only; else -1). */
|
|
79
|
+
previousOffsetOf(instance) {
|
|
80
|
+
return this.history ? this.offsetOf(this.instances + instance) : -1;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Copy `joints × 12` floats from `matrices` (starting at float `offset`) into palette slot
|
|
84
|
+
* `instance`. The upload happens in `flush()`. No allocation.
|
|
85
|
+
*/
|
|
86
|
+
set(instance, matrices, offset = 0) {
|
|
87
|
+
this.check(instance);
|
|
88
|
+
const n = this.instanceFloats;
|
|
89
|
+
if (offset + n > matrices.length) {
|
|
90
|
+
throw new Error(`${this.label}: slot ${instance} needs ${n} floats from ${offset}, got ${matrices.length}`);
|
|
91
|
+
}
|
|
92
|
+
const d = this.data;
|
|
93
|
+
const o = this.offsetOf(instance);
|
|
94
|
+
this.capture(instance);
|
|
95
|
+
for (let i = 0; i < n; i++)
|
|
96
|
+
d[o + i] = matrices[offset + i];
|
|
97
|
+
this.dirty(instance);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Slot `instance`'s `joints × 12` floats to write in place (ws/api-render), for example
|
|
101
|
+
* `skinMatrices(skeleton, world, palette.write(0))` with no staging array of your own. Marks
|
|
102
|
+
* the slot for the next `flush()` (and, with `history`, keeps its current block as the
|
|
103
|
+
* previous one first), so call it each frame you write the slot, before writing. The view is
|
|
104
|
+
* made once per slot; no allocation after that.
|
|
105
|
+
*/
|
|
106
|
+
write(instance) {
|
|
107
|
+
this.check(instance);
|
|
108
|
+
let v = this.views[instance];
|
|
109
|
+
if (!v) {
|
|
110
|
+
const o = this.offsetOf(instance);
|
|
111
|
+
v = this.data.subarray(o, o + this.instanceFloats);
|
|
112
|
+
this.views[instance] = v;
|
|
113
|
+
}
|
|
114
|
+
this.capture(instance);
|
|
115
|
+
this.dirty(instance);
|
|
116
|
+
return v;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The `InstanceParams` that draw with slot `instance` (ws/api-render): `params` is
|
|
120
|
+
* `[0, 0, 0, instance]`, the slot in `params[SKIN_PARAM]`. One object per slot, made on first
|
|
121
|
+
* use; pass it to `frame.mesh(mesh, material, transform, palette.params(i))`.
|
|
122
|
+
*/
|
|
123
|
+
params(instance) {
|
|
124
|
+
this.check(instance);
|
|
125
|
+
let p = this.slotParams[instance];
|
|
126
|
+
if (!p) {
|
|
127
|
+
p = { params: [0, 0, 0, instance] };
|
|
128
|
+
this.slotParams[instance] = p;
|
|
129
|
+
}
|
|
130
|
+
return p;
|
|
131
|
+
}
|
|
132
|
+
/** Reset every joint of slot `instance` to the identity (the mesh's bind pose). */
|
|
133
|
+
setIdentity(instance) {
|
|
134
|
+
this.check(instance);
|
|
135
|
+
const d = this.data;
|
|
136
|
+
let o = this.offsetOf(instance);
|
|
137
|
+
this.capture(instance);
|
|
138
|
+
for (let j = 0; j < this.joints; j++) {
|
|
139
|
+
d.fill(0, o, o + JOINT_FLOATS);
|
|
140
|
+
d[o] = 1;
|
|
141
|
+
d[o + 5] = 1;
|
|
142
|
+
d[o + 10] = 1;
|
|
143
|
+
o += JOINT_FLOATS;
|
|
144
|
+
}
|
|
145
|
+
this.dirty(instance);
|
|
146
|
+
}
|
|
147
|
+
/** Upload the slots written since the last flush in one `writeBuffer`; nothing when clean. */
|
|
148
|
+
flush() {
|
|
149
|
+
const lo = this.dirtyLo;
|
|
150
|
+
const hi = this.dirtyHi;
|
|
151
|
+
if (this.history) {
|
|
152
|
+
// Slots written last flush but not this one move on: previous := current.
|
|
153
|
+
const sLo = Math.max(this.settleLo, 0);
|
|
154
|
+
const sHi = this.settleHi;
|
|
155
|
+
const n = this.instanceFloats;
|
|
156
|
+
for (let i = sLo; i <= sHi; i++) {
|
|
157
|
+
if (this.stamp[i] === this.flushes)
|
|
158
|
+
continue;
|
|
159
|
+
const cur = this.offsetOf(i);
|
|
160
|
+
this.data.copyWithin(this.previousOffsetOf(i), cur, cur + n);
|
|
161
|
+
}
|
|
162
|
+
const uLo = lo > hi ? sLo : sHi < sLo ? lo : Math.min(lo, sLo);
|
|
163
|
+
const uHi = lo > hi ? sHi : Math.max(hi, sHi);
|
|
164
|
+
this.settleLo = lo;
|
|
165
|
+
this.settleHi = hi;
|
|
166
|
+
this.flushes++;
|
|
167
|
+
this.dirtyLo = this.instances;
|
|
168
|
+
this.dirtyHi = -1;
|
|
169
|
+
if (uLo > uHi)
|
|
170
|
+
return;
|
|
171
|
+
const first = this.offsetOf(uLo) * 4;
|
|
172
|
+
const bytes = (uHi - uLo + 1) * n * 4;
|
|
173
|
+
this.device.queue.writeBuffer(this.buffer, first, this.data.buffer, first, bytes);
|
|
174
|
+
const pFirst = this.previousOffsetOf(uLo) * 4;
|
|
175
|
+
this.device.queue.writeBuffer(this.buffer, pFirst, this.data.buffer, pFirst, bytes);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (lo > hi)
|
|
179
|
+
return;
|
|
180
|
+
this.dirtyLo = this.instances;
|
|
181
|
+
this.dirtyHi = -1;
|
|
182
|
+
const first = this.offsetOf(lo) * 4;
|
|
183
|
+
const bytes = (hi - lo + 1) * this.instanceFloats * 4;
|
|
184
|
+
this.device.queue.writeBuffer(this.buffer, first, this.data.buffer, first, bytes);
|
|
185
|
+
}
|
|
186
|
+
/** With history: the first write to a slot in a frame keeps its current block as previous. */
|
|
187
|
+
capture(instance) {
|
|
188
|
+
if (!this.history || this.stamp[instance] === this.flushes)
|
|
189
|
+
return;
|
|
190
|
+
this.stamp[instance] = this.flushes;
|
|
191
|
+
const cur = this.offsetOf(instance);
|
|
192
|
+
this.data.copyWithin(this.previousOffsetOf(instance), cur, cur + this.instanceFloats);
|
|
193
|
+
}
|
|
194
|
+
/** True when a `flush()` would upload something. */
|
|
195
|
+
get isDirty() {
|
|
196
|
+
return this.dirtyLo <= this.dirtyHi;
|
|
197
|
+
}
|
|
198
|
+
destroy() {
|
|
199
|
+
this.buffer.destroy();
|
|
200
|
+
}
|
|
201
|
+
check(instance) {
|
|
202
|
+
if (instance < 0 || instance >= this.instances || !Number.isInteger(instance)) {
|
|
203
|
+
throw new Error(`${this.label}: slot ${instance} out of range (0..${this.instances - 1})`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
dirty(instance) {
|
|
207
|
+
if (instance < this.dirtyLo)
|
|
208
|
+
this.dirtyLo = instance;
|
|
209
|
+
if (instance > this.dirtyHi)
|
|
210
|
+
this.dirtyHi = instance;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Write the joints and weights of vertex `vertex` of a `VERTEX_LAYOUT_SKINNED` buffer, through
|
|
215
|
+
* `bytes`, a `Uint8Array` over the vertex data (`new Uint8Array(vertices.buffer)`). Weights are
|
|
216
|
+
* normalised to sum to 1 and quantised to unorm8 so the four bytes add up to 255. Up to four
|
|
217
|
+
* joints; missing entries read joint 0 with weight 0.
|
|
218
|
+
*/
|
|
219
|
+
export function setVertexSkin(bytes, vertex, joints, weights) {
|
|
220
|
+
const base = vertex * VERTEX_SKINNED_STRIDE;
|
|
221
|
+
let sum = 0;
|
|
222
|
+
for (let k = 0; k < 4; k++)
|
|
223
|
+
sum += k < weights.length ? Math.max(0, weights[k]) : 0;
|
|
224
|
+
const scale = sum > 0 ? 255 / sum : 0;
|
|
225
|
+
let used = 0;
|
|
226
|
+
let largest = 0;
|
|
227
|
+
for (let k = 0; k < 4; k++) {
|
|
228
|
+
const j = k < joints.length ? joints[k] : 0;
|
|
229
|
+
const w = k < weights.length ? Math.round(Math.max(0, weights[k]) * scale) : 0;
|
|
230
|
+
bytes[base + SKIN_JOINTS_BYTE_OFFSET + k] = j;
|
|
231
|
+
bytes[base + SKIN_WEIGHTS_BYTE_OFFSET + k] = w;
|
|
232
|
+
used += w;
|
|
233
|
+
if (w > bytes[base + SKIN_WEIGHTS_BYTE_OFFSET + largest])
|
|
234
|
+
largest = k;
|
|
235
|
+
}
|
|
236
|
+
// Rounding may leave the bytes short of (or past) 255: settle it on the heaviest weight.
|
|
237
|
+
if (sum > 0 && used !== 255) {
|
|
238
|
+
bytes[base + SKIN_WEIGHTS_BYTE_OFFSET + largest] += 255 - used;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offscreen snapshots: a second `Renderer` on the same GPU device that draws one frame into an
|
|
3
|
+
* `OffscreenCanvas` and hands it back as an `ImageBitmap`. Use it to bake still images (icons,
|
|
4
|
+
* thumbnails, previews) with the real materials and post stack, then show them in the DOM.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const shot = new SnapshotRenderer(renderer.device, renderer.format, { width: 512, height: 256 });
|
|
8
|
+
* shot.renderer.post = new PostStack(shot.renderer); // optional
|
|
9
|
+
* const mat = shot.renderer.createMaterial({ … }); // materials belong to shot.renderer
|
|
10
|
+
* const bmp = shot.capture((frame) => frame.sprite(mat, { x: 128, y: 128, w: 200, h: 200 }));
|
|
11
|
+
* ctx2d.drawImage(bmp, 0, 0, 256, 256, 0, 0, 256, 256); // slice cells out of the sheet
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The logical space equals the pixel size, so a draw at (x, y) lands on that pixel.
|
|
15
|
+
*/
|
|
16
|
+
import type { Frame } from './frame.js';
|
|
17
|
+
import { Renderer } from './renderer.js';
|
|
18
|
+
export interface SnapshotOptions {
|
|
19
|
+
/** Output size in pixels (also the logical size). */
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class SnapshotRenderer {
|
|
24
|
+
readonly renderer: Renderer;
|
|
25
|
+
readonly width: number;
|
|
26
|
+
readonly height: number;
|
|
27
|
+
private readonly canvas;
|
|
28
|
+
private readonly context;
|
|
29
|
+
constructor(device: GPUDevice, format: GPUTextureFormat, opts: SnapshotOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Draw one frame (`draw` records into it) and return the result. `time` feeds
|
|
32
|
+
* `globals.time`, so animated materials can be frozen at a chosen moment.
|
|
33
|
+
*/
|
|
34
|
+
capture(draw: (frame: Frame) => void, time?: number): ImageBitmap;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Renderer } from './renderer.js';
|
|
2
|
+
export class SnapshotRenderer {
|
|
3
|
+
renderer;
|
|
4
|
+
width;
|
|
5
|
+
height;
|
|
6
|
+
canvas;
|
|
7
|
+
context;
|
|
8
|
+
constructor(device, format, opts) {
|
|
9
|
+
this.width = Math.max(1, Math.floor(opts.width));
|
|
10
|
+
this.height = Math.max(1, Math.floor(opts.height));
|
|
11
|
+
this.canvas = new OffscreenCanvas(this.width, this.height);
|
|
12
|
+
const context = this.canvas.getContext('webgpu');
|
|
13
|
+
if (!context)
|
|
14
|
+
throw new Error('SnapshotRenderer: no webgpu context on OffscreenCanvas');
|
|
15
|
+
context.configure({ device, format, alphaMode: 'opaque' });
|
|
16
|
+
this.context = context;
|
|
17
|
+
this.renderer = new Renderer({ device, context, format }, { logicalWidth: this.width, logicalHeight: this.height, initialInstances: 64 });
|
|
18
|
+
this.renderer.resize(this.width, this.height);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Draw one frame (`draw` records into it) and return the result. `time` feeds
|
|
22
|
+
* `globals.time`, so animated materials can be frozen at a chosen moment.
|
|
23
|
+
*/
|
|
24
|
+
capture(draw, time = 0) {
|
|
25
|
+
const frame = this.renderer.beginFrame(time, 1 / 60);
|
|
26
|
+
draw(frame);
|
|
27
|
+
this.renderer.endFrame();
|
|
28
|
+
return this.canvas.transferToImageBitmap();
|
|
29
|
+
}
|
|
30
|
+
destroy() {
|
|
31
|
+
this.renderer.destroy();
|
|
32
|
+
this.context.unconfigure();
|
|
33
|
+
}
|
|
34
|
+
}
|