@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,661 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `loadGltf`: a parsed `GltfDocument` → engine meshes (`VERTEX_LAYOUT_3D`, the tangent layout
|
|
3
|
+
* for primitives with `TANGENT`, the skinned layout for skinned ones when a palette is given),
|
|
4
|
+
* one `Transform` per node, one `Texture` per (image, colour space) a material reads, one
|
|
5
|
+
* standard PBR `Material` per glTF material (every map, factor, sampler, alpha mode and
|
|
6
|
+
* `KHR_texture_transform` carried over; `opts.lit: 'lit'` keeps the older base-colour-only
|
|
7
|
+
* material), and a `GltfScene` whose `draw(frame)` pushes one instance per (node, primitive)
|
|
8
|
+
* with no allocation. Images decode through `createImageBitmap` (or `opts.decodeImage`);
|
|
9
|
+
* external URIs come from `opts.resources`, fetched by the game. The engine fetches nothing.
|
|
10
|
+
*
|
|
11
|
+
* Morph targets: a mesh with targets keeps its primitives' base vertex buffers on the CPU and
|
|
12
|
+
* blends them through `anim`'s `createMorphBlender` into a second buffer `draw` uploads with
|
|
13
|
+
* `Mesh.update` when `scene.morph(node).apply()` reported a change. Meshes without targets keep
|
|
14
|
+
* nothing on the CPU.
|
|
15
|
+
*
|
|
16
|
+
* Lights and cameras: `scene.lights` holds the file's `KHR_lights_punctual` lights as the
|
|
17
|
+
* render module's `SunLight` / `PointLight` / `SpotLight` records (push them into
|
|
18
|
+
* `frame.lights`); `scene.cameras` the file's cameras, which `applyGltfCamera` sets on a
|
|
19
|
+
* `Camera`. Material variants (`KHR_materials_variants`): every material is created at load;
|
|
20
|
+
* `scene.setVariant(name)` swaps the material of each mapped draw in place.
|
|
21
|
+
*/
|
|
22
|
+
import { createMorphBlender } from '../anim/morph.js';
|
|
23
|
+
import { mat4 } from '../core/math.js';
|
|
24
|
+
import { Mesh, VERTEX_LAYOUT_3D, VERTEX_LAYOUT_3D_TANGENT, VERTEX_LAYOUT_SKINNED, VERTEX3D_FLOATS, } from '../render/mesh.js';
|
|
25
|
+
import { generateMipmaps } from '../render/mipmap.js';
|
|
26
|
+
import { createStandardMaterial } from '../render/standard.js';
|
|
27
|
+
import { Transform } from '../render/transform.js';
|
|
28
|
+
import { GltfError, } from './gltf.js';
|
|
29
|
+
import { interleaveSkinned } from './gltf-skin.js';
|
|
30
|
+
/** Floats per vertex of `VERTEX_LAYOUT_3D_TANGENT`. */
|
|
31
|
+
const TANGENT_FLOATS = VERTEX_LAYOUT_3D_TANGENT.floats;
|
|
32
|
+
/**
|
|
33
|
+
* Built-in material: base colour texture × factor × vertex colour, lit by the engine's lighting
|
|
34
|
+
* block (`engine_lambert`) plus a faint sky term from above. `params.x` > 0 is a `MASK` cutoff.
|
|
35
|
+
*/
|
|
36
|
+
export const GLTF_LIT_WGSL = /* wgsl */ `
|
|
37
|
+
@group(1) @binding(1) var baseSampler: sampler;
|
|
38
|
+
@group(1) @binding(2) var baseTex: texture_2d<f32>;
|
|
39
|
+
|
|
40
|
+
@fragment fn fs_main(in: VSOut) -> FragOut {
|
|
41
|
+
let c = textureSample(baseTex, baseSampler, in.uv) * in.color;
|
|
42
|
+
if (in.params.x > 0.0 && c.a < in.params.x) { discard; }
|
|
43
|
+
let n = normalize(in.normal);
|
|
44
|
+
let sky = 0.5 + 0.5 * n.y;
|
|
45
|
+
var o: FragOut;
|
|
46
|
+
o.color = vec4f(c.rgb * (engine_lambert(n, in.worldPos) + 0.12 * sky), c.a);
|
|
47
|
+
o.emissive = vec4f(0.0);
|
|
48
|
+
return o;
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
/** The GPU side of one glTF document. Owns what it created; `destroy()` frees it. */
|
|
52
|
+
export class GltfScene {
|
|
53
|
+
/** One per primitive, in document order (mesh 0's primitives, then mesh 1's, …). */
|
|
54
|
+
meshes = [];
|
|
55
|
+
/**
|
|
56
|
+
* One per (image, colour space) a material reads, in first-use order: base colour and
|
|
57
|
+
* emissive maps are sRGB, the rest linear, so an image used both ways is uploaded twice.
|
|
58
|
+
*/
|
|
59
|
+
textures = [];
|
|
60
|
+
/** One per glTF material, built by the loader (empty when `opts.material` was given). */
|
|
61
|
+
materials = [];
|
|
62
|
+
/** The file's `material.name` per glTF material (null when unnamed). */
|
|
63
|
+
materialNames = [];
|
|
64
|
+
/** The palette skinned meshes are bound to (`opts.palette`), or null. */
|
|
65
|
+
palette;
|
|
66
|
+
/** One per document node, parented like the file (`doc.nodes[i]` → `transforms[i]`). */
|
|
67
|
+
transforms = [];
|
|
68
|
+
/** Every draw: one per (node in the default scene, primitive of its mesh). */
|
|
69
|
+
nodes = [];
|
|
70
|
+
/** World-space bounds of the default scene (from the document). */
|
|
71
|
+
bounds;
|
|
72
|
+
/** The document's skins (`skeletonFromSkin(doc, i)` builds the animation module's skeleton). */
|
|
73
|
+
skins;
|
|
74
|
+
/** The document's clips, in the animation module's `AnimationClip` shape. */
|
|
75
|
+
animations;
|
|
76
|
+
/** One per mesh that carries morph targets, in mesh order. */
|
|
77
|
+
morphs = [];
|
|
78
|
+
/** The file's lights as render records (`GltfSceneLights`; empty lists when it has none). */
|
|
79
|
+
lights = { directional: [], points: [], spots: [] };
|
|
80
|
+
/** The file's cameras placed by their nodes (`applyGltfCamera` sets one on a `Camera`). */
|
|
81
|
+
cameras;
|
|
82
|
+
/** The file's `KHR_materials_variants` names (`setVariant` takes one). */
|
|
83
|
+
variants;
|
|
84
|
+
/** Whether the default material or textures were created here (and so destroyed here). */
|
|
85
|
+
ownsMaterials;
|
|
86
|
+
morphByMesh = new Map();
|
|
87
|
+
morphEntries = [];
|
|
88
|
+
doc;
|
|
89
|
+
variantDraws = [];
|
|
90
|
+
resolveMaterial = null;
|
|
91
|
+
litParams = false;
|
|
92
|
+
activeVariant = null;
|
|
93
|
+
constructor(doc, ownsMaterials, palette = null) {
|
|
94
|
+
this.doc = doc;
|
|
95
|
+
this.bounds = { center: [...doc.bounds.center], radius: doc.bounds.radius };
|
|
96
|
+
this.skins = doc.skins;
|
|
97
|
+
this.animations = doc.animations;
|
|
98
|
+
this.ownsMaterials = ownsMaterials;
|
|
99
|
+
this.palette = palette;
|
|
100
|
+
for (const m of doc.materials)
|
|
101
|
+
this.materialNames.push(m.name);
|
|
102
|
+
this.cameras = doc.cameras;
|
|
103
|
+
this.variants = doc.variants;
|
|
104
|
+
}
|
|
105
|
+
/** The active material variant, or null for each primitive's own material. */
|
|
106
|
+
get variant() {
|
|
107
|
+
return this.activeVariant;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Switch every draw with `KHR_materials_variants` mappings to the material `name` binds (a
|
|
111
|
+
* draw no mapping of `name` covers goes back to its own material); null restores every
|
|
112
|
+
* draw's own material. Swaps `material` (and `materialIndex`) in place: no material is
|
|
113
|
+
* created. Throws `GltfError` listing the file's variants for an unknown name.
|
|
114
|
+
*/
|
|
115
|
+
setVariant(name) {
|
|
116
|
+
let v = -1;
|
|
117
|
+
if (name !== null) {
|
|
118
|
+
v = this.variants.indexOf(name);
|
|
119
|
+
if (v < 0) {
|
|
120
|
+
const known = this.variants.length > 0 ? this.variants.join(', ') : 'none';
|
|
121
|
+
throw new GltfError(`variant "${name}" unknown (variants: ${known})`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const vd of this.variantDraws) {
|
|
125
|
+
let mi = vd.base;
|
|
126
|
+
if (v >= 0) {
|
|
127
|
+
for (const m of vd.mappings) {
|
|
128
|
+
if (m.variants.includes(v)) {
|
|
129
|
+
mi = m.material;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
vd.draw.materialIndex = mi;
|
|
135
|
+
if (this.resolveMaterial)
|
|
136
|
+
vd.draw.material = this.resolveMaterial(mi);
|
|
137
|
+
if (this.litParams)
|
|
138
|
+
writeLitParams(vd.draw.params, mi === null ? undefined : this.doc.materials[mi]);
|
|
139
|
+
}
|
|
140
|
+
this.activeVariant = name;
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
/** @internal The loader: how `setVariant` finds a material, and which draws it touches. */
|
|
144
|
+
bindVariants(resolve, litParams, draws) {
|
|
145
|
+
this.resolveMaterial = resolve;
|
|
146
|
+
this.litParams = litParams;
|
|
147
|
+
for (const d of draws)
|
|
148
|
+
this.variantDraws.push(d);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The morph state of the mesh `nodeIndex` (into `GltfDocument.nodes`) draws, or null when the
|
|
152
|
+
* node has no mesh or the mesh no targets. Nodes sharing a mesh share the object.
|
|
153
|
+
*/
|
|
154
|
+
morph(nodeIndex) {
|
|
155
|
+
const mi = this.doc.nodes[nodeIndex]?.mesh;
|
|
156
|
+
if (mi === null || mi === undefined)
|
|
157
|
+
return null;
|
|
158
|
+
return this.morphByMesh.get(mi) ?? null;
|
|
159
|
+
}
|
|
160
|
+
/** @internal Register a mesh's morph state (the loader). */
|
|
161
|
+
addMorph(morph, entries) {
|
|
162
|
+
this.morphs.push(morph);
|
|
163
|
+
this.morphByMesh.set(morph.mesh, morph);
|
|
164
|
+
for (const e of entries)
|
|
165
|
+
this.morphEntries.push(e);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Upload every morphed primitive whose `apply()` changed it, then record every draw into
|
|
169
|
+
* `frame`. Allocation-free.
|
|
170
|
+
*/
|
|
171
|
+
draw(frame) {
|
|
172
|
+
const entries = this.morphEntries;
|
|
173
|
+
for (let i = 0; i < entries.length; i++) {
|
|
174
|
+
const e = entries[i];
|
|
175
|
+
if (!e.dirty)
|
|
176
|
+
continue;
|
|
177
|
+
e.dirty = false;
|
|
178
|
+
e.mesh.update(e.update);
|
|
179
|
+
}
|
|
180
|
+
const nodes = this.nodes;
|
|
181
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
182
|
+
const n = nodes[i];
|
|
183
|
+
frame.mesh(n.mesh, n.material, n.transform, n.params);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
destroy() {
|
|
187
|
+
for (const m of this.meshes)
|
|
188
|
+
m.destroy();
|
|
189
|
+
for (const t of this.textures)
|
|
190
|
+
t.destroy();
|
|
191
|
+
if (this.ownsMaterials)
|
|
192
|
+
for (const m of this.materials)
|
|
193
|
+
m.destroy();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Upload a document to the GPU. Resolves once every image is decoded; everything else is
|
|
198
|
+
* synchronous. Throws `GltfError` for a missing external resource or an undecodable image.
|
|
199
|
+
*/
|
|
200
|
+
export async function loadGltf(renderer, doc, opts = {}) {
|
|
201
|
+
const label = opts.label ?? 'gltf';
|
|
202
|
+
const mips = opts.mips ?? true;
|
|
203
|
+
const lit = opts.lit ?? 'standard';
|
|
204
|
+
const standard = lit === 'standard' && !opts.material;
|
|
205
|
+
const palette = opts.palette ?? null;
|
|
206
|
+
const scene = new GltfScene(doc, !opts.material, palette);
|
|
207
|
+
// Textures: decode every image a material reads, in parallel, then upload one texture per
|
|
208
|
+
// (image, colour space): base colour and emissive maps are sRGB, the rest linear. The older
|
|
209
|
+
// lit material reads base colour only.
|
|
210
|
+
const srgbSlots = ['baseColor', 'emissive'];
|
|
211
|
+
const linearSlots = standard
|
|
212
|
+
? ['metallicRoughness', 'normal', 'occlusion']
|
|
213
|
+
: [];
|
|
214
|
+
const wanted = new Set();
|
|
215
|
+
const imageOf = (ref) => ref ? (doc.textures[ref.index]?.source ?? null) : null;
|
|
216
|
+
for (const gm of doc.materials) {
|
|
217
|
+
for (const slot of srgbSlots) {
|
|
218
|
+
const img = imageOf(gm[slot]);
|
|
219
|
+
if (img !== null)
|
|
220
|
+
wanted.add(`${img}:srgb`);
|
|
221
|
+
}
|
|
222
|
+
for (const slot of linearSlots) {
|
|
223
|
+
const img = imageOf(gm[slot]);
|
|
224
|
+
if (img !== null)
|
|
225
|
+
wanted.add(`${img}:linear`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const needed = new Set();
|
|
229
|
+
for (const key of wanted)
|
|
230
|
+
needed.add(Number(key.split(':')[0]));
|
|
231
|
+
const imageSources = await Promise.all(doc.images.map((img, i) => (needed.has(i) ? decodeImage(img, i, opts) : null)));
|
|
232
|
+
const uploaded = new Map();
|
|
233
|
+
for (let img = 0; img < doc.images.length; img++) {
|
|
234
|
+
const src = imageSources[img];
|
|
235
|
+
if (!src)
|
|
236
|
+
continue;
|
|
237
|
+
for (const srgb of [true, false]) {
|
|
238
|
+
const key = `${img}:${srgb ? 'srgb' : 'linear'}`;
|
|
239
|
+
if (!wanted.has(key))
|
|
240
|
+
continue;
|
|
241
|
+
const tex = renderer.createTexture({
|
|
242
|
+
width: src.width,
|
|
243
|
+
height: src.height,
|
|
244
|
+
mips,
|
|
245
|
+
format: srgb ? 'rgba8unorm-srgb' : 'rgba8unorm',
|
|
246
|
+
label: srgb ? `${label}:image${img}` : `${label}:image${img}:linear`,
|
|
247
|
+
});
|
|
248
|
+
renderer.device.queue.copyExternalImageToTexture({ source: src }, { texture: tex.texture }, [
|
|
249
|
+
src.width,
|
|
250
|
+
src.height,
|
|
251
|
+
]);
|
|
252
|
+
if (tex.mipLevels > 1)
|
|
253
|
+
generateMipmaps(renderer.device, tex);
|
|
254
|
+
uploaded.set(key, tex);
|
|
255
|
+
scene.textures.push(tex);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
for (const src of imageSources)
|
|
259
|
+
if (src && 'close' in src)
|
|
260
|
+
src.close();
|
|
261
|
+
const textureFor = (ref, srgb) => {
|
|
262
|
+
const img = imageOf(ref);
|
|
263
|
+
return img === null ? undefined : uploaded.get(`${img}:${srgb ? 'srgb' : 'linear'}`);
|
|
264
|
+
};
|
|
265
|
+
// Materials: one engine material per glTF material (textures are bound per material).
|
|
266
|
+
const materialFor = new Map();
|
|
267
|
+
const defaultMaterial = () => {
|
|
268
|
+
let m = materialFor.get(null);
|
|
269
|
+
if (!m) {
|
|
270
|
+
m =
|
|
271
|
+
opts.material ??
|
|
272
|
+
(standard
|
|
273
|
+
? createStandardMaterial(renderer, {
|
|
274
|
+
label: `${label}:default`,
|
|
275
|
+
metallic: 1,
|
|
276
|
+
roughness: 1,
|
|
277
|
+
...(palette ? { skin: palette } : {}),
|
|
278
|
+
})
|
|
279
|
+
: createLitMaterial(renderer, `${label}:default`, 'opaque', mips));
|
|
280
|
+
materialFor.set(null, m);
|
|
281
|
+
if (!opts.material)
|
|
282
|
+
scene.materials.push(m);
|
|
283
|
+
}
|
|
284
|
+
return m;
|
|
285
|
+
};
|
|
286
|
+
if (!opts.material) {
|
|
287
|
+
doc.materials.forEach((gm, i) => {
|
|
288
|
+
let m;
|
|
289
|
+
if (standard) {
|
|
290
|
+
const d = standardDesc(doc, gm, `${label}:material${i}`, textureFor, mips);
|
|
291
|
+
if (palette)
|
|
292
|
+
d.skin = palette;
|
|
293
|
+
m = createStandardMaterial(renderer, d);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
m = createLitMaterial(renderer, `${label}:material${i}`, gm.alphaMode === 'BLEND' ? 'alpha' : 'opaque', mips);
|
|
297
|
+
const t = textureFor(gm.baseColor, true);
|
|
298
|
+
if (t)
|
|
299
|
+
m.setTexture(0, t);
|
|
300
|
+
}
|
|
301
|
+
materialFor.set(i, m);
|
|
302
|
+
scene.materials.push(m);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// Meshes: one per primitive, interleaved into VERTEX_LAYOUT_3D, the tangent layout (TANGENT)
|
|
306
|
+
// or the skinned layout (JOINTS_0 and a palette; it has no tangent slot).
|
|
307
|
+
const meshIndex = doc.meshes.map((gm, mi) => {
|
|
308
|
+
const targetCount = gm.primitives[0]?.targets.length ?? 0;
|
|
309
|
+
const weights = gm.weights ? new Float32Array(gm.weights) : new Float32Array(targetCount);
|
|
310
|
+
const entries = [];
|
|
311
|
+
const meshes = gm.primitives.map((p, pi) => {
|
|
312
|
+
const skinned = palette !== null && p.joints instanceof Uint8Array;
|
|
313
|
+
const tangent = p.tangent !== null;
|
|
314
|
+
let layout = VERTEX_LAYOUT_3D;
|
|
315
|
+
let vertices;
|
|
316
|
+
if (skinned) {
|
|
317
|
+
layout = VERTEX_LAYOUT_SKINNED;
|
|
318
|
+
vertices = new Float32Array(interleaveSkinned(p).vertices);
|
|
319
|
+
}
|
|
320
|
+
else if (tangent) {
|
|
321
|
+
layout = VERTEX_LAYOUT_3D_TANGENT;
|
|
322
|
+
vertices = interleave3dTangent(p);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
vertices = interleave3d(p);
|
|
326
|
+
}
|
|
327
|
+
const mesh = new Mesh(renderer.device, {
|
|
328
|
+
label: `${label}:mesh${mi}.${pi}`,
|
|
329
|
+
layout,
|
|
330
|
+
vertices,
|
|
331
|
+
indices: p.indices,
|
|
332
|
+
bounds: { center: [...p.bounds.center], radius: p.bounds.radius },
|
|
333
|
+
});
|
|
334
|
+
scene.meshes.push(mesh);
|
|
335
|
+
if (targetCount > 0) {
|
|
336
|
+
// Keep the base on the CPU only here; the blender writes into a second buffer.
|
|
337
|
+
const blender = createMorphBlender(vertices, p.targets, { floats: layout.stride / 4 }, weights);
|
|
338
|
+
entries.push({
|
|
339
|
+
blender,
|
|
340
|
+
mesh,
|
|
341
|
+
update: { vertices: new Float32Array(vertices.length) },
|
|
342
|
+
dirty: false,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return mesh;
|
|
346
|
+
});
|
|
347
|
+
if (targetCount > 0) {
|
|
348
|
+
scene.addMorph({
|
|
349
|
+
mesh: mi,
|
|
350
|
+
weights,
|
|
351
|
+
targetCount,
|
|
352
|
+
blenders: entries.map((e) => e.blender),
|
|
353
|
+
apply() {
|
|
354
|
+
let any = false;
|
|
355
|
+
for (let i = 0; i < entries.length; i++) {
|
|
356
|
+
const e = entries[i];
|
|
357
|
+
if (e.blender.apply(e.update.vertices)) {
|
|
358
|
+
e.dirty = true;
|
|
359
|
+
any = true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return any;
|
|
363
|
+
},
|
|
364
|
+
}, entries);
|
|
365
|
+
}
|
|
366
|
+
return meshes;
|
|
367
|
+
});
|
|
368
|
+
// Transforms: one per node, parented like the file.
|
|
369
|
+
for (const n of doc.nodes) {
|
|
370
|
+
const t = new Transform();
|
|
371
|
+
t.setPosition(n.translation[0], n.translation[1], n.translation[2]);
|
|
372
|
+
t.setQuaternion(n.rotation[0], n.rotation[1], n.rotation[2], n.rotation[3]);
|
|
373
|
+
t.setScale(n.scale[0], n.scale[1], n.scale[2]);
|
|
374
|
+
scene.transforms.push(t);
|
|
375
|
+
}
|
|
376
|
+
doc.nodes.forEach((n, i) => {
|
|
377
|
+
if (n.parent !== null)
|
|
378
|
+
scene.transforms[i].parent = scene.transforms[n.parent];
|
|
379
|
+
});
|
|
380
|
+
// Draws: every node in the default scene with a mesh, one per primitive.
|
|
381
|
+
const variantDraws = [];
|
|
382
|
+
for (const ni of doc.sceneNodes) {
|
|
383
|
+
const n = doc.nodes[ni];
|
|
384
|
+
if (n.mesh === null)
|
|
385
|
+
continue;
|
|
386
|
+
const mi = n.mesh;
|
|
387
|
+
doc.meshes[mi].primitives.forEach((p, pi) => {
|
|
388
|
+
const gm = p.material !== null ? doc.materials[p.material] : undefined;
|
|
389
|
+
const material = opts.material ??
|
|
390
|
+
(p.material !== null ? materialFor.get(p.material) : undefined) ??
|
|
391
|
+
defaultMaterial();
|
|
392
|
+
const draw = {
|
|
393
|
+
node: ni,
|
|
394
|
+
transform: scene.transforms[ni],
|
|
395
|
+
mesh: meshIndex[mi][pi],
|
|
396
|
+
material,
|
|
397
|
+
params: standard ? paramsStandard() : paramsFor(gm),
|
|
398
|
+
skin: n.skin,
|
|
399
|
+
materialIndex: p.material,
|
|
400
|
+
};
|
|
401
|
+
scene.nodes.push(draw);
|
|
402
|
+
if (p.variants.length > 0) {
|
|
403
|
+
variantDraws.push({ draw, base: p.material, mappings: p.variants });
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
scene.bindVariants(opts.material
|
|
408
|
+
? null
|
|
409
|
+
: (i) => (i !== null ? materialFor.get(i) : undefined) ?? defaultMaterial(), !standard && !opts.material, variantDraws);
|
|
410
|
+
// Lights: glTF units → the render module's records.
|
|
411
|
+
const scale = opts.lightScale ?? 1;
|
|
412
|
+
for (const l of doc.lights) {
|
|
413
|
+
const k = l.intensity * scale;
|
|
414
|
+
const color = new Float32Array([l.color[0] * k, l.color[1] * k, l.color[2] * k]);
|
|
415
|
+
const radius = l.range ?? 16 * Math.sqrt(Math.max(k, 0));
|
|
416
|
+
if (l.type === 'directional') {
|
|
417
|
+
scene.lights.directional.push(sunLight(new Float32Array(l.direction), color));
|
|
418
|
+
}
|
|
419
|
+
else if (l.type === 'point') {
|
|
420
|
+
scene.lights.points.push({ position: new Float32Array(l.position), color, radius });
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
scene.lights.spots.push({
|
|
424
|
+
position: new Float32Array(l.position),
|
|
425
|
+
direction: new Float32Array(l.direction),
|
|
426
|
+
color,
|
|
427
|
+
radius,
|
|
428
|
+
innerAngle: l.innerConeAngle ?? 0,
|
|
429
|
+
outerAngle: l.outerConeAngle ?? Math.PI / 4,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return scene;
|
|
434
|
+
}
|
|
435
|
+
/** A `SunLight` record, the shape of `Lights.sun`. */
|
|
436
|
+
function sunLight(direction, color) {
|
|
437
|
+
return { direction, color };
|
|
438
|
+
}
|
|
439
|
+
const orthoScratch = new Float32Array(16);
|
|
440
|
+
/**
|
|
441
|
+
* Set `camera` to a glTF camera: its projection (perspective `yfov`, the file's `aspectRatio`
|
|
442
|
+
* or `aspect`, `znear`, `zfar` or an infinite far plane; orthographic `xmag` / `ymag` half
|
|
443
|
+
* extents and its depth range) and its node's view (`GltfCamera.view`). Turns depth test,
|
|
444
|
+
* depth write and culling on. Allocation-free; returns `camera`.
|
|
445
|
+
*/
|
|
446
|
+
export function applyGltfCamera(camera, c, aspect) {
|
|
447
|
+
if (c.type === 'perspective') {
|
|
448
|
+
camera.setPerspective(c.yfov, c.aspectRatio ?? aspect, c.znear, c.zfar ?? Infinity);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
const far = c.zfar ?? c.znear + 1;
|
|
452
|
+
camera.setProjection(mat4.ortho(orthoScratch, -c.xmag, c.xmag, -c.ymag, c.ymag, c.znear, far));
|
|
453
|
+
camera.depthTest = true;
|
|
454
|
+
camera.depthWrite = true;
|
|
455
|
+
camera.cull = true;
|
|
456
|
+
}
|
|
457
|
+
camera.setView(c.view);
|
|
458
|
+
return camera;
|
|
459
|
+
}
|
|
460
|
+
function createLitMaterial(renderer, label, blend, mips) {
|
|
461
|
+
return renderer.createMaterial({
|
|
462
|
+
label,
|
|
463
|
+
wgsl: GLTF_LIT_WGSL,
|
|
464
|
+
textures: 1,
|
|
465
|
+
blend,
|
|
466
|
+
sampler: mips ? 'linear-mip-repeat' : 'linear-repeat',
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* A `StandardMaterialDesc` for one glTF material: maps through `textureFor` (sRGB for base
|
|
471
|
+
* colour and emissive, linear otherwise), factors, alpha mode, double-sidedness, the sampler
|
|
472
|
+
* of the base colour texture (else the first slot with one; `gltfSamplerKind`) and the
|
|
473
|
+
* `KHR_texture_transform` of the base colour slot (else the first slot with one): the
|
|
474
|
+
* standard material has one sampler and one uv transform for every map, and reads
|
|
475
|
+
* `TEXCOORD_0` only.
|
|
476
|
+
*/
|
|
477
|
+
function standardDesc(doc, gm, label, textureFor, mips) {
|
|
478
|
+
const d = {
|
|
479
|
+
label,
|
|
480
|
+
baseColorFactor: gm.baseColorFactor,
|
|
481
|
+
metallic: gm.metallicFactor,
|
|
482
|
+
roughness: gm.roughnessFactor,
|
|
483
|
+
normalScale: gm.normalScale,
|
|
484
|
+
emissiveFactor: gm.emissiveFactor,
|
|
485
|
+
alphaMode: gm.alphaMode === 'BLEND' ? 'blend' : gm.alphaMode === 'MASK' ? 'mask' : 'opaque',
|
|
486
|
+
alphaCutoff: gm.alphaCutoff,
|
|
487
|
+
doubleSided: gm.doubleSided,
|
|
488
|
+
};
|
|
489
|
+
const base = textureFor(gm.baseColor, true);
|
|
490
|
+
const mr = textureFor(gm.metallicRoughness, false);
|
|
491
|
+
const normal = textureFor(gm.normal, false);
|
|
492
|
+
const occlusion = textureFor(gm.occlusion, false);
|
|
493
|
+
const emissive = textureFor(gm.emissive, true);
|
|
494
|
+
if (base)
|
|
495
|
+
d.baseColor = base;
|
|
496
|
+
if (mr)
|
|
497
|
+
d.metallicRoughness = mr;
|
|
498
|
+
if (normal)
|
|
499
|
+
d.normal = normal;
|
|
500
|
+
if (occlusion)
|
|
501
|
+
d.occlusion = occlusion;
|
|
502
|
+
if (emissive)
|
|
503
|
+
d.emissive = emissive;
|
|
504
|
+
const slots = [gm.baseColor, gm.metallicRoughness, gm.normal, gm.occlusion, gm.emissive];
|
|
505
|
+
let sampler;
|
|
506
|
+
let transform = null;
|
|
507
|
+
for (const ref of slots) {
|
|
508
|
+
if (!ref)
|
|
509
|
+
continue;
|
|
510
|
+
if (!sampler)
|
|
511
|
+
sampler = doc.textures[ref.index]?.sampler;
|
|
512
|
+
if (!transform)
|
|
513
|
+
transform = ref.transform;
|
|
514
|
+
}
|
|
515
|
+
if (sampler)
|
|
516
|
+
d.sampler = gltfSamplerKind(sampler, mips);
|
|
517
|
+
if (transform)
|
|
518
|
+
d.uvTransform = uvTransformOf(transform);
|
|
519
|
+
// Per-map texCoord and transform, and the occlusion strength (ws/render-4).
|
|
520
|
+
if (gm.name)
|
|
521
|
+
d.name = gm.name;
|
|
522
|
+
if (gm.occlusionStrength !== 1)
|
|
523
|
+
d.occlusionStrength = gm.occlusionStrength;
|
|
524
|
+
const names = ['baseColor', 'metallicRoughness', 'normal', 'occlusion', 'emissive'];
|
|
525
|
+
for (let k = 0; k < slots.length; k++) {
|
|
526
|
+
const ref = slots[k];
|
|
527
|
+
if (!ref)
|
|
528
|
+
continue;
|
|
529
|
+
const texCoord = ref.texCoord === 1 ? 1 : 0;
|
|
530
|
+
const own = ref.transform && ref.transform !== transform;
|
|
531
|
+
if (texCoord === 0 && !own)
|
|
532
|
+
continue;
|
|
533
|
+
d.maps ??= {};
|
|
534
|
+
d.maps[names[k]] = {
|
|
535
|
+
texCoord,
|
|
536
|
+
...(own ? { uvTransform: uvTransformOf(ref.transform) } : {}),
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return d;
|
|
540
|
+
}
|
|
541
|
+
function uvTransformOf(t) {
|
|
542
|
+
return [t.scale[0], t.scale[1], t.offset[0], t.offset[1], t.rotation];
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* The engine sampler nearest a glTF one: nearest magnification → `nearest-mip-clamp` (or
|
|
546
|
+
* `nearest-clamp` without mips; the engine has no nearest-repeat), linear → `linear-clamp`
|
|
547
|
+
* when both wraps clamp, else `linear-mip-repeat` (`linear-repeat` without mips; mirrored
|
|
548
|
+
* repeat is treated as repeat). `mips` false, or a glTF `minFilter` without a mipmap mode,
|
|
549
|
+
* picks the level-0 sampler.
|
|
550
|
+
*/
|
|
551
|
+
export function gltfSamplerKind(sampler, mips) {
|
|
552
|
+
const mip = mips && sampler.mipmapFilter !== null;
|
|
553
|
+
if (sampler.magFilter === 'nearest')
|
|
554
|
+
return mip ? 'nearest-mip-clamp' : 'nearest-clamp';
|
|
555
|
+
const clamp = sampler.wrapS === 'clamp-to-edge' && sampler.wrapT === 'clamp-to-edge';
|
|
556
|
+
if (clamp)
|
|
557
|
+
return 'linear-clamp';
|
|
558
|
+
return mip ? 'linear-mip-repeat' : 'linear-repeat';
|
|
559
|
+
}
|
|
560
|
+
function paramsStandard() {
|
|
561
|
+
return { tint: new Float32Array([1, 1, 1, 1]), params: new Float32Array(4) };
|
|
562
|
+
}
|
|
563
|
+
function paramsFor(gm) {
|
|
564
|
+
const p = { tint: new Float32Array(4), params: new Float32Array(4) };
|
|
565
|
+
writeLitParams(p, gm);
|
|
566
|
+
return p;
|
|
567
|
+
}
|
|
568
|
+
/** The lit material's per-draw values for `gm`: base colour factor as tint, cutoff as `x`. */
|
|
569
|
+
function writeLitParams(p, gm) {
|
|
570
|
+
// The loader made both arrays (`paramsFor`); a game that replaced them keeps its own.
|
|
571
|
+
const tint = gm ? gm.baseColorFactor : [1, 1, 1, 1];
|
|
572
|
+
if (p.tint instanceof Float32Array)
|
|
573
|
+
p.tint.set(tint);
|
|
574
|
+
if (p.params instanceof Float32Array)
|
|
575
|
+
p.params[0] = gm?.alphaMode === 'MASK' ? gm.alphaCutoff : 0;
|
|
576
|
+
}
|
|
577
|
+
/** `x, y, z, nx, ny, nz, u, v, r, g, b, a` per vertex (the `VERTEX_LAYOUT_3D` float order). */
|
|
578
|
+
export function interleave3d(p) {
|
|
579
|
+
const n = p.vertexCount;
|
|
580
|
+
const out = new Float32Array(n * VERTEX3D_FLOATS);
|
|
581
|
+
for (let i = 0; i < n; i++) {
|
|
582
|
+
const o = i * VERTEX3D_FLOATS;
|
|
583
|
+
out[o] = p.position[i * 3];
|
|
584
|
+
out[o + 1] = p.position[i * 3 + 1];
|
|
585
|
+
out[o + 2] = p.position[i * 3 + 2];
|
|
586
|
+
out[o + 3] = p.normal[i * 3];
|
|
587
|
+
out[o + 4] = p.normal[i * 3 + 1];
|
|
588
|
+
out[o + 5] = p.normal[i * 3 + 2];
|
|
589
|
+
out[o + 6] = p.uv0[i * 2];
|
|
590
|
+
out[o + 7] = p.uv0[i * 2 + 1];
|
|
591
|
+
out[o + 8] = p.color0[i * 4];
|
|
592
|
+
out[o + 9] = p.color0[i * 4 + 1];
|
|
593
|
+
out[o + 10] = p.color0[i * 4 + 2];
|
|
594
|
+
out[o + 11] = p.color0[i * 4 + 3];
|
|
595
|
+
}
|
|
596
|
+
return out;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* `VERTEX_LAYOUT_3D_TANGENT`: the 12 floats of `interleave3d` then `tangent.xyzw` per vertex.
|
|
600
|
+
* A primitive without `TANGENT` gets `(1, 0, 0, 1)`.
|
|
601
|
+
*/
|
|
602
|
+
export function interleave3dTangent(p) {
|
|
603
|
+
const n = p.vertexCount;
|
|
604
|
+
const out = new Float32Array(n * TANGENT_FLOATS);
|
|
605
|
+
const t = p.tangent;
|
|
606
|
+
for (let i = 0; i < n; i++) {
|
|
607
|
+
const o = i * TANGENT_FLOATS;
|
|
608
|
+
out[o] = p.position[i * 3];
|
|
609
|
+
out[o + 1] = p.position[i * 3 + 1];
|
|
610
|
+
out[o + 2] = p.position[i * 3 + 2];
|
|
611
|
+
out[o + 3] = p.normal[i * 3];
|
|
612
|
+
out[o + 4] = p.normal[i * 3 + 1];
|
|
613
|
+
out[o + 5] = p.normal[i * 3 + 2];
|
|
614
|
+
out[o + 6] = p.uv0[i * 2];
|
|
615
|
+
out[o + 7] = p.uv0[i * 2 + 1];
|
|
616
|
+
out[o + 8] = p.color0[i * 4];
|
|
617
|
+
out[o + 9] = p.color0[i * 4 + 1];
|
|
618
|
+
out[o + 10] = p.color0[i * 4 + 2];
|
|
619
|
+
out[o + 11] = p.color0[i * 4 + 3];
|
|
620
|
+
if (t) {
|
|
621
|
+
out[o + 12] = t[i * 4];
|
|
622
|
+
out[o + 13] = t[i * 4 + 1];
|
|
623
|
+
out[o + 14] = t[i * 4 + 2];
|
|
624
|
+
out[o + 15] = t[i * 4 + 3];
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
out[o + 12] = 1;
|
|
628
|
+
out[o + 15] = 1;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return out;
|
|
632
|
+
}
|
|
633
|
+
async function decodeImage(img, index, opts) {
|
|
634
|
+
let bytes = img.bytes;
|
|
635
|
+
if (img.uri !== null) {
|
|
636
|
+
const res = opts.resources?.[img.uri];
|
|
637
|
+
if (res === undefined)
|
|
638
|
+
throw new GltfError(`image ${index}: missing external resource "${img.uri}"`);
|
|
639
|
+
if (!(res instanceof ArrayBuffer))
|
|
640
|
+
return res;
|
|
641
|
+
bytes = new Uint8Array(res);
|
|
642
|
+
}
|
|
643
|
+
if (!bytes)
|
|
644
|
+
throw new GltfError(`image ${index}: no bytes to decode`);
|
|
645
|
+
const decode = opts.decodeImage ?? defaultDecode;
|
|
646
|
+
try {
|
|
647
|
+
return await decode(bytes, img.mimeType);
|
|
648
|
+
}
|
|
649
|
+
catch (e) {
|
|
650
|
+
throw new GltfError(`image ${index}: decode failed (${img.mimeType ?? 'unknown type'}): ${e instanceof Error ? e.message : String(e)}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function defaultDecode(bytes, mimeType) {
|
|
654
|
+
if (typeof createImageBitmap !== 'function') {
|
|
655
|
+
throw new GltfError('createImageBitmap is not available; pass opts.decodeImage');
|
|
656
|
+
}
|
|
657
|
+
const copy = new Uint8Array(bytes.byteLength);
|
|
658
|
+
copy.set(bytes);
|
|
659
|
+
const blob = new Blob([copy], mimeType ? { type: mimeType } : undefined);
|
|
660
|
+
return createImageBitmap(blob, { colorSpaceConversion: 'none' });
|
|
661
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type GltfDocument, type GltfPrimitive } from './gltf.js';
|
|
2
|
+
/** Interleaved skinned vertices, ready for a `Mesh` in `VERTEX_LAYOUT_SKINNED`. */
|
|
3
|
+
export interface SkinnedVertices {
|
|
4
|
+
/** `vertexCount * VERTEX_SKINNED_STRIDE` bytes: `x y z nx ny nz u v r g b a` as f32, 4 joint bytes, 4 weight bytes. */
|
|
5
|
+
vertices: ArrayBuffer;
|
|
6
|
+
layout: 'skinned';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Pack a skinned primitive into the skinned vertex layout: the 3D floats, then the four joint
|
|
10
|
+
* indices as bytes and the four weights as `unorm8` (renormalised to sum to 1 first and
|
|
11
|
+
* rounded so the four bytes sum to 255, so quantisation never scales the vertex). Throws when
|
|
12
|
+
* the primitive has no `JOINTS_0` or a joint index above 255 (the layout's `uint8x4`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function interleaveSkinned(p: GltfPrimitive): SkinnedVertices;
|
|
15
|
+
/**
|
|
16
|
+
* The animation module's `Skeleton` shape (see the file comment). The skeleton spans every
|
|
17
|
+
* node of the document, so `GltfAnimationChannel.node` indexes `rest` and a pose directly;
|
|
18
|
+
* `joints[j]` names the node that drives joint `j` of the skin.
|
|
19
|
+
*/
|
|
20
|
+
export interface GltfSkeleton {
|
|
21
|
+
/** Parent node per node, -1 for a root. */
|
|
22
|
+
parents: Int16Array;
|
|
23
|
+
/** Rest pose from each node's TRS: 10 floats per node, `tx ty tz qx qy qz qw sx sy sz`. */
|
|
24
|
+
rest: Float32Array;
|
|
25
|
+
/** 12 floats (3×4 rows) per joint, from `GltfSkin.inverseBind`. */
|
|
26
|
+
inverseBind: Float32Array;
|
|
27
|
+
/** Node index per joint. */
|
|
28
|
+
joints: Uint16Array;
|
|
29
|
+
/**
|
|
30
|
+
* One name per node (the file's `node.name`, `node<i>` when unnamed), so `anim`'s
|
|
31
|
+
* `createSocket(skeleton, 'hand_r')` resolves joints by name.
|
|
32
|
+
*/
|
|
33
|
+
names: string[];
|
|
34
|
+
}
|
|
35
|
+
/** Build a skeleton for `doc.skins[skinIndex]` over every node of the document, named after them. */
|
|
36
|
+
export declare function skeletonFromSkin(doc: GltfDocument, skinIndex: number): GltfSkeleton;
|