@drawcall/lod 0.1.2 → 0.3.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/README.md +13 -70
- package/dist/at.d.ts +2 -0
- package/dist/at.js +8 -0
- package/dist/at.js.map +1 -0
- package/dist/bake.d.ts +22 -0
- package/dist/bake.js +88 -0
- package/dist/bake.js.map +1 -0
- package/dist/baked/codec.d.ts +5 -5
- package/dist/baked/codec.js +58 -158
- package/dist/baked/codec.js.map +1 -1
- package/dist/baked/coverage.d.ts +6 -3
- package/dist/baked/coverage.js +6 -3
- package/dist/baked/coverage.js.map +1 -1
- package/dist/baked/fields.d.ts +9 -0
- package/dist/baked/fields.js +22 -0
- package/dist/baked/fields.js.map +1 -0
- package/dist/baked/index.d.ts +16 -6
- package/dist/baked/index.js +23 -21
- package/dist/baked/index.js.map +1 -1
- package/dist/baked/interior/faces.d.ts +4 -3
- package/dist/baked/interior/faces.js +13 -10
- package/dist/baked/interior/faces.js.map +1 -1
- package/dist/baked/interior/material.d.ts +7 -10
- package/dist/baked/interior/material.js +29 -36
- package/dist/baked/interior/material.js.map +1 -1
- package/dist/baked/interior/rooms.js +1 -1
- package/dist/baked/interior/rooms.js.map +1 -1
- package/dist/baked/low.d.ts +2 -2
- package/dist/baked/low.js +9 -8
- package/dist/baked/low.js.map +1 -1
- package/dist/baked/raster.js +6 -6
- package/dist/baked/raster.js.map +1 -1
- package/dist/baked/textures.d.ts +17 -0
- package/dist/baked/textures.js +95 -0
- package/dist/baked/textures.js.map +1 -0
- package/dist/baked/transfer.js +19 -18
- package/dist/baked/transfer.js.map +1 -1
- package/dist/baked/unwrap.js +4 -3
- package/dist/baked/unwrap.js.map +1 -1
- package/dist/baked/xatlas.js.map +1 -1
- package/dist/codec/container.d.ts +8 -0
- package/dist/codec/container.js +63 -0
- package/dist/codec/container.js.map +1 -0
- package/dist/codec/mesh.d.ts +8 -0
- package/dist/codec/mesh.js +220 -0
- package/dist/codec/mesh.js.map +1 -0
- package/dist/dispose.d.ts +11 -4
- package/dist/dispose.js +39 -12
- package/dist/dispose.js.map +1 -1
- package/dist/gpu.d.ts +39 -0
- package/dist/gpu.js +41 -0
- package/dist/gpu.js.map +1 -0
- package/dist/impostor/bake/atlas.d.ts +4 -4
- package/dist/impostor/bake/atlas.js +12 -12
- package/dist/impostor/bake/atlas.js.map +1 -1
- package/dist/impostor/bake/fit.d.ts +8 -0
- package/dist/impostor/bake/fit.js +28 -0
- package/dist/impostor/bake/fit.js.map +1 -0
- package/dist/impostor/bake/index.d.ts +23 -14
- package/dist/impostor/bake/index.js +42 -134
- package/dist/impostor/bake/index.js.map +1 -1
- package/dist/impostor/bake/materials.d.ts +3 -3
- package/dist/impostor/bake/materials.js +60 -12
- package/dist/impostor/bake/materials.js.map +1 -1
- package/dist/impostor/bake/sheet.d.ts +8 -0
- package/dist/impostor/bake/sheet.js +90 -0
- package/dist/impostor/bake/sheet.js.map +1 -0
- package/dist/impostor/bake/source.d.ts +2 -2
- package/dist/impostor/bake/source.js +8 -19
- package/dist/impostor/bake/source.js.map +1 -1
- package/dist/impostor/codec.d.ts +5 -11
- package/dist/impostor/codec.js +37 -121
- package/dist/impostor/codec.js.map +1 -1
- package/dist/impostor/impostor.d.ts +31 -7
- package/dist/impostor/impostor.js +21 -6
- package/dist/impostor/impostor.js.map +1 -1
- package/dist/impostor/ktx2/encode.d.ts +26 -0
- package/dist/impostor/ktx2/encode.js +117 -0
- package/dist/impostor/ktx2/encode.js.map +1 -0
- package/dist/impostor/ktx2/transcode.d.ts +3 -0
- package/dist/impostor/ktx2/transcode.js +99 -0
- package/dist/impostor/ktx2/transcode.js.map +1 -0
- package/dist/impostor/ktx2/uastc.d.ts +7 -0
- package/dist/impostor/ktx2/uastc.js +64 -0
- package/dist/impostor/ktx2/uastc.js.map +1 -0
- package/dist/impostor/ktx2/wasm/encoder.d.ts +4 -0
- package/dist/impostor/ktx2/wasm/encoder.js +10 -0
- package/dist/impostor/ktx2/wasm/encoder.js.map +1 -0
- package/dist/impostor/ktx2/wasm/transcoder.d.ts +3 -0
- package/dist/impostor/ktx2/wasm/transcoder.js +9 -0
- package/dist/impostor/ktx2/wasm/transcoder.js.map +1 -0
- package/dist/impostor/ktx2/worker.d.ts +1 -0
- package/dist/impostor/ktx2/worker.js +12 -0
- package/dist/impostor/ktx2/worker.js.map +1 -0
- package/dist/impostor/mesh/card.d.ts +3 -3
- package/dist/impostor/mesh/card.js +11 -8
- package/dist/impostor/mesh/card.js.map +1 -1
- package/dist/impostor/mesh/index.d.ts +10 -7
- package/dist/impostor/mesh/index.js +15 -18
- package/dist/impostor/mesh/index.js.map +1 -1
- package/dist/impostor/mesh/material.d.ts +24 -13
- package/dist/impostor/mesh/material.js +67 -51
- package/dist/impostor/mesh/material.js.map +1 -1
- package/dist/impostor/mesh/surface.d.ts +20 -16
- package/dist/impostor/mesh/surface.js +81 -58
- package/dist/impostor/mesh/surface.js.map +1 -1
- package/dist/impostor/mesh/textures.d.ts +3 -3
- package/dist/impostor/mesh/textures.js +24 -34
- package/dist/impostor/mesh/textures.js.map +1 -1
- package/dist/impostor/octahedral.d.ts +1 -8
- package/dist/impostor/octahedral.js +3 -18
- package/dist/impostor/octahedral.js.map +1 -1
- package/dist/index.d.ts +16 -10
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/instanced/camera.d.ts +46 -0
- package/dist/instanced/camera.js +70 -0
- package/dist/instanced/camera.js.map +1 -0
- package/dist/instanced/chunk.d.ts +97 -0
- package/dist/instanced/chunk.js +156 -0
- package/dist/instanced/chunk.js.map +1 -0
- package/dist/instanced/chunks.d.ts +60 -0
- package/dist/instanced/chunks.js +208 -0
- package/dist/instanced/chunks.js.map +1 -0
- package/dist/instanced/cull.d.ts +28 -0
- package/dist/instanced/cull.js +22 -0
- package/dist/instanced/cull.js.map +1 -0
- package/dist/instanced/index.d.ts +96 -92
- package/dist/instanced/index.js +229 -512
- package/dist/instanced/index.js.map +1 -1
- package/dist/instanced/key.d.ts +19 -0
- package/dist/instanced/key.js +45 -0
- package/dist/instanced/key.js.map +1 -0
- package/dist/instanced/levels.d.ts +60 -0
- package/dist/instanced/levels.js +130 -0
- package/dist/instanced/levels.js.map +1 -0
- package/dist/instanced/lists.d.ts +70 -0
- package/dist/instanced/lists.js +133 -0
- package/dist/instanced/lists.js.map +1 -0
- package/dist/instanced/measure.d.ts +28 -0
- package/dist/instanced/measure.js +203 -0
- package/dist/instanced/measure.js.map +1 -0
- package/dist/instanced/meshes.d.ts +46 -14
- package/dist/instanced/meshes.js +137 -22
- package/dist/instanced/meshes.js.map +1 -1
- package/dist/instanced/mirror.d.ts +20 -0
- package/dist/instanced/mirror.js +37 -0
- package/dist/instanced/mirror.js.map +1 -0
- package/dist/instanced/pages/buffers.d.ts +37 -0
- package/dist/instanced/pages/buffers.js +15 -0
- package/dist/instanced/pages/buffers.js.map +1 -0
- package/dist/instanced/pages/chunk.d.ts +51 -0
- package/dist/instanced/pages/chunk.js +81 -0
- package/dist/instanced/pages/chunk.js.map +1 -0
- package/dist/instanced/pages/index.d.ts +74 -0
- package/dist/instanced/pages/index.js +269 -0
- package/dist/instanced/pages/index.js.map +1 -0
- package/dist/instanced/pages/passes.d.ts +21 -0
- package/dist/instanced/pages/passes.js +52 -0
- package/dist/instanced/pages/passes.js.map +1 -0
- package/dist/instanced/pages/slots.d.ts +11 -0
- package/dist/instanced/pages/slots.js +90 -0
- package/dist/instanced/pages/slots.js.map +1 -0
- package/dist/instanced/pages/workgroup.d.ts +14 -0
- package/dist/instanced/pages/workgroup.js +38 -0
- package/dist/instanced/pages/workgroup.js.map +1 -0
- package/dist/instanced/raycast.d.ts +15 -0
- package/dist/instanced/raycast.js +46 -0
- package/dist/instanced/raycast.js.map +1 -0
- package/dist/instanced/rows.d.ts +108 -0
- package/dist/instanced/rows.js +209 -0
- package/dist/instanced/rows.js.map +1 -0
- package/dist/instanced/shape.d.ts +25 -0
- package/dist/instanced/shape.js +51 -0
- package/dist/instanced/shape.js.map +1 -0
- package/dist/instanced/sort.d.ts +63 -0
- package/dist/instanced/sort.js +162 -0
- package/dist/instanced/sort.js.map +1 -0
- package/dist/instanced/update.d.ts +30 -0
- package/dist/instanced/update.js +207 -0
- package/dist/instanced/update.js.map +1 -0
- package/dist/levels/bounds.d.ts +21 -0
- package/dist/levels/bounds.js +42 -0
- package/dist/levels/bounds.js.map +1 -0
- package/dist/levels/cameras.d.ts +48 -0
- package/dist/levels/cameras.js +122 -0
- package/dist/levels/cameras.js.map +1 -0
- package/dist/levels/compile/contexts.d.ts +30 -0
- package/dist/levels/compile/contexts.js +18 -0
- package/dist/levels/compile/contexts.js.map +1 -0
- package/dist/levels/compile/index.d.ts +39 -0
- package/dist/levels/compile/index.js +185 -0
- package/dist/levels/compile/index.js.map +1 -0
- package/dist/levels/compile/pipelines.d.ts +26 -0
- package/dist/levels/compile/pipelines.js +177 -0
- package/dist/levels/compile/pipelines.js.map +1 -0
- package/dist/levels/compiles.d.ts +29 -0
- package/dist/levels/compiles.js +50 -0
- package/dist/levels/compiles.js.map +1 -0
- package/dist/levels/draw.d.ts +102 -0
- package/dist/levels/draw.js +401 -0
- package/dist/levels/draw.js.map +1 -0
- package/dist/levels/fade.d.ts +69 -0
- package/dist/levels/fade.js +150 -0
- package/dist/levels/fade.js.map +1 -0
- package/dist/levels/index.d.ts +99 -0
- package/dist/levels/index.js +155 -0
- package/dist/levels/index.js.map +1 -0
- package/dist/levels/item.d.ts +38 -0
- package/dist/levels/item.js +97 -0
- package/dist/levels/item.js.map +1 -0
- package/dist/levels/load.d.ts +31 -0
- package/dist/levels/load.js +142 -0
- package/dist/levels/load.js.map +1 -0
- package/dist/levels/manager.d.ts +159 -0
- package/dist/levels/manager.js +339 -0
- package/dist/levels/manager.js.map +1 -0
- package/dist/{material.js → levels/material.js} +13 -7
- package/dist/levels/material.js.map +1 -0
- package/dist/levels/renderer.d.ts +29 -0
- package/dist/levels/renderer.js +41 -0
- package/dist/levels/renderer.js.map +1 -0
- package/dist/levels/requests.d.ts +49 -0
- package/dist/levels/requests.js +95 -0
- package/dist/levels/requests.js.map +1 -0
- package/dist/levels/screen.d.ts +14 -0
- package/dist/levels/screen.js +21 -0
- package/dist/levels/screen.js.map +1 -0
- package/dist/levels/wait.d.ts +27 -0
- package/dist/levels/wait.js +61 -0
- package/dist/levels/wait.js.map +1 -0
- package/dist/loader/build.d.ts +10 -0
- package/dist/loader/build.js +28 -0
- package/dist/loader/build.js.map +1 -0
- package/dist/loader/cache.d.ts +12 -15
- package/dist/loader/cache.js +64 -33
- package/dist/loader/cache.js.map +1 -1
- package/dist/loader/context.d.ts +46 -0
- package/dist/loader/context.js +91 -0
- package/dist/loader/context.js.map +1 -0
- package/dist/loader/dependencies.d.ts +32 -0
- package/dist/loader/dependencies.js +113 -0
- package/dist/loader/dependencies.js.map +1 -0
- package/dist/loader/index.d.ts +62 -0
- package/dist/loader/index.js +284 -0
- package/dist/loader/index.js.map +1 -0
- package/dist/loader/level.d.ts +41 -0
- package/dist/loader/level.js +140 -0
- package/dist/loader/level.js.map +1 -0
- package/dist/loader/request.d.ts +87 -0
- package/dist/loader/request.js +59 -0
- package/dist/loader/request.js.map +1 -0
- package/dist/loader/url.d.ts +16 -0
- package/dist/loader/url.js +35 -0
- package/dist/loader/url.js.map +1 -0
- package/dist/lod.d.ts +79 -49
- package/dist/lod.js +209 -153
- package/dist/lod.js.map +1 -1
- package/dist/meshopt.d.ts +6 -0
- package/dist/meshopt.js +19 -0
- package/dist/meshopt.js.map +1 -0
- package/dist/simplify/cards.d.ts +14 -0
- package/dist/simplify/cards.js +128 -0
- package/dist/simplify/cards.js.map +1 -0
- package/dist/{simplify.d.ts → simplify/index.d.ts} +7 -4
- package/dist/{simplify.js → simplify/index.js} +42 -22
- package/dist/simplify/index.js.map +1 -0
- package/dist/{bounds.d.ts → source/detail.d.ts} +4 -13
- package/dist/{bounds.js → source/detail.js} +62 -32
- package/dist/source/detail.js.map +1 -0
- package/dist/source/{error.d.ts → deviation.d.ts} +3 -3
- package/dist/source/{error.js → deviation.js} +12 -12
- package/dist/source/deviation.js.map +1 -0
- package/dist/source/{shading.d.ts → evaluator.d.ts} +10 -10
- package/dist/source/{shading.js → evaluator.js} +5 -5
- package/dist/source/evaluator.js.map +1 -0
- package/dist/source/{trace.d.ts → raycaster.d.ts} +6 -6
- package/dist/source/{trace.js → raycaster.js} +8 -8
- package/dist/source/raycaster.js.map +1 -0
- package/dist/source/{texels.d.ts → sampler.d.ts} +1 -1
- package/dist/source/{texels.js → sampler.js} +3 -3
- package/dist/source/sampler.js.map +1 -0
- package/dist/source/source.d.ts +2 -2
- package/dist/source/source.js +2 -2
- package/dist/source/source.js.map +1 -1
- package/dist/source/surface.js +1 -1
- package/dist/source/surface.js.map +1 -1
- package/dist/task.d.ts +6 -0
- package/dist/{pause.js → task.js} +5 -5
- package/dist/task.js.map +1 -0
- package/dist/three.d.ts +20 -19
- package/dist/three.js +29 -35
- package/dist/three.js.map +1 -1
- package/dist/tsl.d.ts +10 -14
- package/dist/tsl.js +12 -47
- package/dist/tsl.js.map +1 -1
- package/dist/typegpu.d.ts +37 -0
- package/dist/typegpu.js +37 -0
- package/dist/typegpu.js.map +1 -0
- package/dist/wind/bounds.js +2 -2
- package/dist/wind/bounds.js.map +1 -1
- package/dist/wind/hooks.d.ts +7 -4
- package/dist/wind/hooks.js +5 -2
- package/dist/wind/hooks.js.map +1 -1
- package/dist/wind/index.d.ts +4 -4
- package/dist/wind/index.js +43 -40
- package/dist/wind/index.js.map +1 -1
- package/dist/wind/sway.d.ts +4 -1
- package/dist/wind/sway.js +4 -1
- package/dist/wind/sway.js.map +1 -1
- package/package.json +24 -8
- package/skills/lod/SKILL.md +147 -108
- package/dist/bounds.js.map +0 -1
- package/dist/fade.d.ts +0 -44
- package/dist/fade.js +0 -78
- package/dist/fade.js.map +0 -1
- package/dist/impostor/cache.d.ts +0 -15
- package/dist/impostor/cache.js +0 -44
- package/dist/impostor/cache.js.map +0 -1
- package/dist/instanced/args.d.ts +0 -20
- package/dist/instanced/args.js +0 -77
- package/dist/instanced/args.js.map +0 -1
- package/dist/instanced/bounds.d.ts +0 -50
- package/dist/instanced/bounds.js +0 -271
- package/dist/instanced/bounds.js.map +0 -1
- package/dist/instanced/dirty.d.ts +0 -12
- package/dist/instanced/dirty.js +0 -61
- package/dist/instanced/dirty.js.map +0 -1
- package/dist/instanced/select.d.ts +0 -84
- package/dist/instanced/select.js +0 -264
- package/dist/instanced/select.js.map +0 -1
- package/dist/lazy.d.ts +0 -64
- package/dist/lazy.js +0 -187
- package/dist/lazy.js.map +0 -1
- package/dist/levels.d.ts +0 -72
- package/dist/levels.js +0 -146
- package/dist/levels.js.map +0 -1
- package/dist/loader/dispose.d.ts +0 -3
- package/dist/loader/dispose.js +0 -25
- package/dist/loader/dispose.js.map +0 -1
- package/dist/loader.d.ts +0 -99
- package/dist/loader.js +0 -234
- package/dist/loader.js.map +0 -1
- package/dist/material.js.map +0 -1
- package/dist/pause.d.ts +0 -6
- package/dist/pause.js.map +0 -1
- package/dist/renderer.d.ts +0 -21
- package/dist/renderer.js +0 -83
- package/dist/renderer.js.map +0 -1
- package/dist/simplify.js.map +0 -1
- package/dist/source/error.js.map +0 -1
- package/dist/source/shading.js.map +0 -1
- package/dist/source/texels.js.map +0 -1
- package/dist/source/trace.js.map +0 -1
- package/dist/view.d.ts +0 -30
- package/dist/view.js +0 -75
- package/dist/view.js.map +0 -1
- /package/dist/{material.d.ts → levels/material.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet.js","sourceRoot":"","sources":["../../../src/impostor/bake/sheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Object3D } from "three/webgpu";
|
|
2
|
-
/**
|
|
3
|
-
export declare function sourceForBake(object: Object3D
|
|
2
|
+
/** A copy of `object` to bake, which the bake may move and change; ImpostorMeshes are refused. */
|
|
3
|
+
export declare function sourceForBake(object: Object3D): Object3D;
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
2
|
-
import { forEachMesh } from "../../
|
|
2
|
+
import { forEachMesh } from "../../source/detail.js";
|
|
3
3
|
import { isImpostorMesh } from "../../three.js";
|
|
4
|
-
/**
|
|
5
|
-
export function sourceForBake(object
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (excluded.length > 0)
|
|
12
|
-
object.children = children.filter((child) => !excluded.includes(child));
|
|
13
|
-
forEachMesh(object, (mesh) => {
|
|
14
|
-
if (isImpostorMesh(mesh))
|
|
15
|
-
throw new Error(`bakeImpostor: cannot bake an ImpostorMesh ("${mesh.name}"); bake from its source instead`);
|
|
16
|
-
});
|
|
17
|
-
return clone(object);
|
|
18
|
-
}
|
|
19
|
-
finally {
|
|
20
|
-
object.children = children;
|
|
21
|
-
}
|
|
4
|
+
/** A copy of `object` to bake, which the bake may move and change; ImpostorMeshes are refused. */
|
|
5
|
+
export function sourceForBake(object) {
|
|
6
|
+
forEachMesh(object, (mesh) => {
|
|
7
|
+
if (isImpostorMesh(mesh))
|
|
8
|
+
throw new Error(`bakeImpostor: cannot bake an ImpostorMesh ("${mesh.name}"); bake from its source instead`);
|
|
9
|
+
});
|
|
10
|
+
return clone(object);
|
|
22
11
|
}
|
|
23
12
|
//# sourceMappingURL=source.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/impostor/bake/source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/impostor/bake/source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAAC,MAAgB;IAC5C,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAC3B,IAAI,cAAc,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,IAAI,kCAAkC,CAAC,CAAC;IACxI,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC"}
|
package/dist/impostor/codec.d.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { type Impostor } from "./impostor.js";
|
|
2
2
|
/**
|
|
3
|
-
* Serializes `impostor
|
|
4
|
-
*
|
|
5
|
-
* "impostor" key.
|
|
3
|
+
* Serializes a baked `impostor`: every field but the layers as JSON, then one KTX2 file per map of GPU-compressible
|
|
4
|
+
* Basis UASTC, encoded in workers. A few seconds for a 1024 atlas.
|
|
6
5
|
*/
|
|
7
|
-
export declare function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare function decodeImpostor(input: Input): Impostor;
|
|
11
|
-
/** Inflate cache files asynchronously with the runtime's native zlib decoder. */
|
|
12
|
-
export declare function decodeImpostorAsync(input: Input): Promise<Impostor>;
|
|
13
|
-
export declare function fromBase64(text: string): Uint8Array;
|
|
14
|
-
export {};
|
|
6
|
+
export declare function encodeImpostorAsync(impostor: Impostor): Promise<Uint8Array>;
|
|
7
|
+
/** Parses a file written by `encodeImpostorAsync`, transcoding its maps off the main thread to a format the GPU takes. */
|
|
8
|
+
export declare function decodeImpostorAsync(bytes: Uint8Array): Promise<Impostor>;
|
package/dist/impostor/codec.js
CHANGED
|
@@ -1,137 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { read } from "ktx-parse";
|
|
2
|
+
import { RGBAFormat } from "three/webgpu";
|
|
3
|
+
import { pack, unpack } from "../codec/container.js";
|
|
3
4
|
import { validateImpostor } from "./impostor.js";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { encodeLayer } from "./ktx2/encode.js";
|
|
6
|
+
import { transcode } from "./ktx2/transcode.js";
|
|
7
|
+
const srgb = (map) => map === "base" || map === "emissive";
|
|
6
8
|
/**
|
|
7
|
-
* Serializes `impostor
|
|
8
|
-
*
|
|
9
|
-
* "impostor" key.
|
|
9
|
+
* Serializes a baked `impostor`: every field but the layers as JSON, then one KTX2 file per map of GPU-compressible
|
|
10
|
+
* Basis UASTC, encoded in workers. A few seconds for a 1024 atlas.
|
|
10
11
|
*/
|
|
11
|
-
export function
|
|
12
|
+
export async function encodeImpostorAsync(impostor) {
|
|
12
13
|
validateImpostor(impostor);
|
|
13
14
|
const { layers, ...meta } = impostor;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
22
|
-
const ktx = createDefaultContainer();
|
|
23
|
-
ktx.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
|
24
|
-
ktx.typeSize = 1;
|
|
25
|
-
ktx.pixelWidth = meta.size;
|
|
26
|
-
ktx.pixelHeight = meta.size;
|
|
27
|
-
ktx.layerCount = layers.length;
|
|
28
|
-
ktx.levelCount = levels.length;
|
|
29
|
-
ktx.supercompressionScheme = KHR_SUPERCOMPRESSION_ZLIB;
|
|
30
|
-
ktx.levels = levels;
|
|
31
|
-
// UNORM data must declare a linear transfer; base/emissive are sRGB-encoded but the
|
|
32
|
-
// renderer decodes them itself, as it does with the linear normal/orm layers.
|
|
33
|
-
const channels = [KHR_DF_CHANNEL_RGBSDA_RED, KHR_DF_CHANNEL_RGBSDA_GREEN, KHR_DF_CHANNEL_RGBSDA_BLUE, KHR_DF_CHANNEL_RGBSDA_ALPHA];
|
|
34
|
-
for (const dfd of ktx.dataFormatDescriptor) {
|
|
35
|
-
dfd.colorModel = KHR_DF_MODEL_RGBSDA;
|
|
36
|
-
dfd.transferFunction = KHR_DF_TRANSFER_LINEAR;
|
|
37
|
-
dfd.bytesPlane = [4, 0, 0, 0, 0, 0, 0, 0];
|
|
38
|
-
dfd.samples = channels.map((channelType, i) => ({
|
|
39
|
-
bitOffset: i * 8,
|
|
40
|
-
bitLength: 7, // stored as bits - 1
|
|
41
|
-
channelType,
|
|
42
|
-
samplePosition: [0, 0, 0, 0],
|
|
43
|
-
sampleLower: 0,
|
|
44
|
-
sampleUpper: 255,
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
ktx.keyValue[KEY] = JSON.stringify(meta);
|
|
48
|
-
return write(ktx);
|
|
49
|
-
}
|
|
50
|
-
/** Parses a file written by `encodeImpostor`, given as bytes or base64. */
|
|
51
|
-
export function decodeImpostor(input) {
|
|
52
|
-
const file = parse(input);
|
|
53
|
-
const levels = file.levels.map(({ data, length }, m) => attempt(`level ${m} does not inflate`, () => unzlibSync(data, { out: new Uint8Array(length) })));
|
|
54
|
-
return decoded(file, levels);
|
|
15
|
+
const files = await Promise.all(layers.map((layer, i) => {
|
|
16
|
+
const map = impostor.maps[i];
|
|
17
|
+
if (!map || layer.format !== RGBAFormat)
|
|
18
|
+
throw new Error("encodeImpostorAsync: encode a baked impostor; this one holds compressed blocks");
|
|
19
|
+
return encodeLayer({ levels: layer.mipmaps, size: impostor.size, srgb: srgb(map) });
|
|
20
|
+
}));
|
|
21
|
+
return pack(meta, files);
|
|
55
22
|
}
|
|
56
|
-
/**
|
|
57
|
-
export async function decodeImpostorAsync(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
23
|
+
/** Parses a file written by `encodeImpostorAsync`, transcoding its maps off the main thread to a format the GPU takes. */
|
|
24
|
+
export async function decodeImpostorAsync(bytes) {
|
|
25
|
+
const { header, files } = await unpack(bytes, fail);
|
|
26
|
+
if (typeof header !== "object" || header === null)
|
|
27
|
+
fail("metadata is not an object");
|
|
28
|
+
const size = Reflect.get(header, "size");
|
|
29
|
+
const layers = await Promise.all(files.map(async (file, i) => {
|
|
30
|
+
let ktx;
|
|
31
|
+
try {
|
|
32
|
+
ktx = read(file);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
fail(`map ${i} is not a KTX2 file`, error);
|
|
36
|
+
}
|
|
37
|
+
if (ktx.pixelWidth !== size || ktx.pixelHeight !== size)
|
|
38
|
+
fail(`map ${i} is ${ktx.pixelWidth}x${ktx.pixelHeight}, not the atlas size`);
|
|
62
39
|
try {
|
|
63
|
-
|
|
64
|
-
return new Uint8Array(await new Response(stream).arrayBuffer());
|
|
40
|
+
return await transcode(file);
|
|
65
41
|
}
|
|
66
42
|
catch (error) {
|
|
67
|
-
|
|
43
|
+
fail(`map ${i} does not transcode`, error);
|
|
68
44
|
}
|
|
69
45
|
}));
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
function parse(input) {
|
|
73
|
-
const bytes = typeof input === "string" ? attempt("not base64", () => fromBase64(input)) : input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
74
|
-
// ktx-parse reads through `bytes.buffer` without checking the view's end, so a truncated
|
|
75
|
-
// view would read past it; give it a buffer of exactly the file instead.
|
|
76
|
-
const file = bytes.byteLength === bytes.buffer.byteLength ? bytes : bytes.slice();
|
|
77
|
-
const ktx = attempt("not a KTX2 container", () => read(file));
|
|
78
|
-
if (ktx.vkFormat !== VK_FORMAT_R8G8B8A8_UNORM)
|
|
79
|
-
fail(`vkFormat ${ktx.vkFormat} is not R8G8B8A8_UNORM`);
|
|
80
|
-
if (ktx.supercompressionScheme !== KHR_SUPERCOMPRESSION_ZLIB)
|
|
81
|
-
fail(`supercompression ${ktx.supercompressionScheme} is not zlib`);
|
|
82
|
-
if (ktx.pixelWidth !== ktx.pixelHeight)
|
|
83
|
-
fail(`atlas is ${ktx.pixelWidth}x${ktx.pixelHeight}, not square`);
|
|
84
|
-
const json = ktx.keyValue[KEY];
|
|
85
|
-
if (!(json instanceof Uint8Array))
|
|
86
|
-
fail(`missing "${KEY}" metadata`);
|
|
87
|
-
// ktx-parse returns values of keys not starting with "KTX" as raw bytes, NUL included.
|
|
88
|
-
const meta = attempt("metadata is not JSON", () => JSON.parse(new TextDecoder().decode(json).replace(/\0$/, "")));
|
|
89
|
-
if (typeof meta !== "object" || meta === null)
|
|
90
|
-
fail("metadata is not an object");
|
|
91
|
-
const levels = ktx.levels.map((level, m) => {
|
|
92
|
-
const bytes = (ktx.pixelWidth >> m) ** 2 * 4;
|
|
93
|
-
if (level.uncompressedByteLength !== bytes * ktx.layerCount)
|
|
94
|
-
fail(`level ${m} size does not match the atlas`);
|
|
95
|
-
return { data: level.levelData, length: level.uncompressedByteLength };
|
|
96
|
-
});
|
|
97
|
-
return { meta, layerCount: ktx.layerCount, levels };
|
|
98
|
-
}
|
|
99
|
-
function decoded(file, levels) {
|
|
100
|
-
levels.forEach((raw, m) => {
|
|
101
|
-
if (raw.length !== file.levels[m]?.length)
|
|
102
|
-
fail(`level ${m} inflates to the wrong size`);
|
|
103
|
-
});
|
|
104
|
-
// Layers share one inflated buffer per mip, in KTX2's layer-major order.
|
|
105
|
-
const layers = Array.from({ length: file.layerCount }, (_, i) => levels.map((raw) => raw.subarray((i * raw.length) / file.layerCount, ((i + 1) * raw.length) / file.layerCount)));
|
|
106
|
-
const impostor = { ...file.meta, layers };
|
|
46
|
+
const impostor = { ...header, layers };
|
|
107
47
|
validateImpostor(impostor);
|
|
108
48
|
return impostor;
|
|
109
49
|
}
|
|
110
|
-
function fail(why) {
|
|
111
|
-
throw new Error(`Invalid impostor file: ${why}
|
|
112
|
-
}
|
|
113
|
-
/** Runs `run`, turning any throw into an "Invalid impostor file" error. */
|
|
114
|
-
function attempt(why, run) {
|
|
115
|
-
try {
|
|
116
|
-
return run();
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
throw invalid(why, error);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function invalid(why, error) {
|
|
123
|
-
return new Error(`Invalid impostor file: ${why} (${error instanceof Error ? error.message : String(error)})`, { cause: error });
|
|
124
|
-
}
|
|
125
|
-
export function fromBase64(text) {
|
|
126
|
-
// Native where available (Node 25+, current browsers); the fallback covers the rest.
|
|
127
|
-
const native = Reflect.get(Uint8Array, "fromBase64");
|
|
128
|
-
const decoded = typeof native === "function" ? Reflect.apply(native, Uint8Array, [text]) : undefined;
|
|
129
|
-
if (decoded instanceof Uint8Array)
|
|
130
|
-
return decoded;
|
|
131
|
-
const binary = atob(text);
|
|
132
|
-
const bytes = new Uint8Array(binary.length);
|
|
133
|
-
for (let i = 0; i < binary.length; i++)
|
|
134
|
-
bytes[i] = binary.charCodeAt(i);
|
|
135
|
-
return bytes;
|
|
50
|
+
function fail(why, cause) {
|
|
51
|
+
throw new Error(`Invalid impostor file: ${why}`, { cause });
|
|
136
52
|
}
|
|
137
53
|
//# sourceMappingURL=codec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/impostor/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/impostor/codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { RGBAFormat, type CompressedPixelFormat } from "three/webgpu";
|
|
1
2
|
/** Which part of the view sphere the atlas covers. */
|
|
2
3
|
export type ImpostorLayout = "hemi" | "full";
|
|
3
4
|
/**
|
|
4
|
-
* The atlas maps, in the order they are stored. Each is one
|
|
5
|
+
* The atlas maps, in the order they are stored. Each is one RGBA layer:
|
|
5
6
|
*
|
|
6
7
|
* - `base`: base colour (sRGB) in RGB, coverage in A.
|
|
7
8
|
* - `normalDepth`: an object-space normal n in RGB (`n * 0.5 + 0.5`), depth in A. The
|
|
@@ -13,6 +14,18 @@ export type ImpostorLayout = "hemi" | "full";
|
|
|
13
14
|
*/
|
|
14
15
|
export declare const MAPS: readonly ["base", "normalDepth", "orm", "emissive"];
|
|
15
16
|
export type ImpostorMap = (typeof MAPS)[number];
|
|
17
|
+
/**
|
|
18
|
+
* One map's mip chain, `size >> level` square, from `size` down to one texel per frame (`frames` square). The levels
|
|
19
|
+
* are baked, not filtered from level 0.
|
|
20
|
+
*/
|
|
21
|
+
export interface ImpostorLayer {
|
|
22
|
+
/**
|
|
23
|
+
* RGBAFormat: 4 bytes a texel, as baked. A decoded impostor holds the block-compressed format its decoder transcoded
|
|
24
|
+
* to for the GPU, or RGBAFormat where the GPU takes none.
|
|
25
|
+
*/
|
|
26
|
+
format: typeof RGBAFormat | CompressedPixelFormat;
|
|
27
|
+
mipmaps: Uint8Array[];
|
|
28
|
+
}
|
|
16
29
|
/**
|
|
17
30
|
* A baked octahedral impostor: plain data, no GPU resources.
|
|
18
31
|
*
|
|
@@ -25,7 +38,7 @@ export type ImpostorMap = (typeof MAPS)[number];
|
|
|
25
38
|
* toward the camera that baked the frame and 0 is away from it.
|
|
26
39
|
*/
|
|
27
40
|
export interface Impostor {
|
|
28
|
-
version:
|
|
41
|
+
version: 4;
|
|
29
42
|
layout: ImpostorLayout;
|
|
30
43
|
/** frames per atlas side */
|
|
31
44
|
frames: number;
|
|
@@ -45,22 +58,33 @@ export interface Impostor {
|
|
|
45
58
|
*/
|
|
46
59
|
specular?: [number, number, number, number];
|
|
47
60
|
/**
|
|
48
|
-
* One per entry in `maps
|
|
49
|
-
*
|
|
50
|
-
* filtered from level 0. An ImpostorMesh's textures share these arrays, so they stay in
|
|
51
|
-
* memory while the impostor is referenced, ready for `encodeImpostor`.
|
|
61
|
+
* One per entry in `maps`. An ImpostorMesh's textures share these arrays, so they stay in memory while the impostor is
|
|
62
|
+
* referenced, ready for `encodeImpostorAsync` when they are RGBAFormat.
|
|
52
63
|
*/
|
|
53
|
-
layers:
|
|
64
|
+
layers: ImpostorLayer[];
|
|
54
65
|
}
|
|
55
66
|
export declare function boxCentre(b: Impostor["box"]): [number, number, number];
|
|
56
67
|
/** Half the box's edges. */
|
|
57
68
|
export declare function boxExtent(b: Impostor["box"]): [number, number, number];
|
|
58
69
|
/** Radius of the sphere around the box: the depth channel's unit. */
|
|
59
70
|
export declare function boundingRadius(b: Impostor["box"]): number;
|
|
71
|
+
/**
|
|
72
|
+
* Empty border around the object in every frame, as a fraction of the frame's half
|
|
73
|
+
* size. It keeps mip levels from blending a frame's silhouette into its neighbour.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PAD = 0.06;
|
|
76
|
+
/**
|
|
77
|
+
* `texelPixels` of any impostor baked at `resolution`, at least: a frame fitted to the source's bounding sphere, the
|
|
78
|
+
* widest it can be. The default `maxPixels` of an impostor level a loader describes before building it.
|
|
79
|
+
*/
|
|
80
|
+
export declare const framePixels: (resolution?: number) => number;
|
|
60
81
|
/**
|
|
61
82
|
* On-screen height of the object at which two atlas texels span one pixel: the default
|
|
62
83
|
* `LodLevel.maxPixels` of an impostor. An impostor blends filtered reads of several
|
|
63
84
|
* views, so it keeps the source's colour detail only down to about two texels per pixel.
|
|
85
|
+
* A LodLoader describes its levels before baking them, so its impostor levels default to
|
|
86
|
+
* `framePixels` instead: this height for a frame fitted to the bounding sphere, up to about
|
|
87
|
+
* 1.5 times lower than for the frame the bake fits.
|
|
64
88
|
*/
|
|
65
89
|
export declare function texelPixels(impostor: Pick<Impostor, "size" | "frames" | "box" | "halfSize">): number;
|
|
66
90
|
/** Throws unless `value` is a usable impostor. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { RGBAFormat } from "three/webgpu";
|
|
1
2
|
/**
|
|
2
|
-
* The atlas maps, in the order they are stored. Each is one
|
|
3
|
+
* The atlas maps, in the order they are stored. Each is one RGBA layer:
|
|
3
4
|
*
|
|
4
5
|
* - `base`: base colour (sRGB) in RGB, coverage in A.
|
|
5
6
|
* - `normalDepth`: an object-space normal n in RGB (`n * 0.5 + 0.5`), depth in A. The
|
|
@@ -21,10 +22,23 @@ export function boxExtent(b) {
|
|
|
21
22
|
export function boundingRadius(b) {
|
|
22
23
|
return Math.hypot(b[3] - b[0], b[4] - b[1], b[5] - b[2]) / 2;
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Empty border around the object in every frame, as a fraction of the frame's half
|
|
27
|
+
* size. It keeps mip levels from blending a frame's silhouette into its neighbour.
|
|
28
|
+
*/
|
|
29
|
+
export const PAD = 0.06;
|
|
30
|
+
/**
|
|
31
|
+
* `texelPixels` of any impostor baked at `resolution`, at least: a frame fitted to the source's bounding sphere, the
|
|
32
|
+
* widest it can be. The default `maxPixels` of an impostor level a loader describes before building it.
|
|
33
|
+
*/
|
|
34
|
+
export const framePixels = (resolution = 128) => 2 ** Math.floor(Math.log2(resolution)) / (2 * (1 + PAD));
|
|
24
35
|
/**
|
|
25
36
|
* On-screen height of the object at which two atlas texels span one pixel: the default
|
|
26
37
|
* `LodLevel.maxPixels` of an impostor. An impostor blends filtered reads of several
|
|
27
38
|
* views, so it keeps the source's colour detail only down to about two texels per pixel.
|
|
39
|
+
* A LodLoader describes its levels before baking them, so its impostor levels default to
|
|
40
|
+
* `framePixels` instead: this height for a frame fitted to the bounding sphere, up to about
|
|
41
|
+
* 1.5 times lower than for the frame the bake fits.
|
|
28
42
|
*/
|
|
29
43
|
export function texelPixels(impostor) {
|
|
30
44
|
const cell = impostor.size / impostor.frames;
|
|
@@ -42,7 +56,7 @@ export function validateImpostor(value) {
|
|
|
42
56
|
fail("not an object");
|
|
43
57
|
const fields = value;
|
|
44
58
|
const { version, layout, frames, size, box, halfSize, maps, specular, layers } = fields;
|
|
45
|
-
if (version !==
|
|
59
|
+
if (version !== 4)
|
|
46
60
|
fail(`unsupported version ${String(version)}; bake it again`);
|
|
47
61
|
if (layout !== "hemi" && layout !== "full")
|
|
48
62
|
fail(`unknown layout "${String(layout)}"`);
|
|
@@ -67,12 +81,13 @@ export function validateImpostor(value) {
|
|
|
67
81
|
fail(`frame size ${cell} is not a power of two`);
|
|
68
82
|
const levels = Math.log2(cell) + 1;
|
|
69
83
|
for (const layer of layers) {
|
|
70
|
-
if (!Array.isArray(layer) || layer.length !== levels)
|
|
84
|
+
if (typeof layer !== "object" || layer === null || !Array.isArray(layer.mipmaps) || layer.mipmaps.length !== levels)
|
|
71
85
|
fail(`every layer must be a mip chain of ${levels} levels`);
|
|
72
|
-
layer.
|
|
86
|
+
const rgba = layer.format === RGBAFormat;
|
|
87
|
+
layer.mipmaps.forEach((level, m) => {
|
|
73
88
|
const bytes = (size >> m) ** 2 * 4;
|
|
74
|
-
if (!(level instanceof Uint8Array) || level.length !== bytes)
|
|
75
|
-
fail(`mip level ${m} must be a Uint8Array of ${bytes} bytes`);
|
|
89
|
+
if (!(level instanceof Uint8Array) || (rgba ? level.length !== bytes : !level.length))
|
|
90
|
+
fail(`mip level ${m} must be a Uint8Array${rgba ? ` of ${bytes} bytes` : ""}`);
|
|
76
91
|
});
|
|
77
92
|
}
|
|
78
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impostor.js","sourceRoot":"","sources":["../../src/impostor/impostor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"impostor.js","sourceRoot":"","sources":["../../src/impostor/impostor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** One map's RGBA8 mip levels, `size >> level` square. */
|
|
2
|
+
export interface Layer {
|
|
3
|
+
levels: Uint8Array[];
|
|
4
|
+
size: number;
|
|
5
|
+
/** Whether the texels are sRGB-encoded colour; otherwise linear data. */
|
|
6
|
+
srgb: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** What the worker encodes: RGBA8 rows of a mip level, `width` wide and `height` high. */
|
|
9
|
+
export interface Job {
|
|
10
|
+
data: Uint8Array;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
srgb: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** What the worker answers a job with. */
|
|
16
|
+
export type Reply = {
|
|
17
|
+
file: Uint8Array;
|
|
18
|
+
} | {
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* One map as a KTX2 file of Basis UASTC. Each level encodes as `parts` strips of rows, by default one per worker, so
|
|
23
|
+
* that a map's top level, which holds three quarters of its texels, takes all workers; the strips' and levels' files
|
|
24
|
+
* are then joined. Takes about a second per million texels and worker.
|
|
25
|
+
*/
|
|
26
|
+
export declare function encodeLayer({ levels, size, srgb }: Layer, parts?: number): Promise<Uint8Array>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { read, write } from "ktx-parse";
|
|
2
|
+
// Read when the module loads, which also happens in Node, as for a .glts warmup; Node before 21 has no navigator.
|
|
3
|
+
const cores = globalThis.navigator?.hardwareConcurrency ?? 4;
|
|
4
|
+
/**
|
|
5
|
+
* A worker per core but one, since a cold ladder's encodes take far longer than its bakes; at most 8, since each holds
|
|
6
|
+
* 100 to 250 MB of WebAssembly memory.
|
|
7
|
+
*/
|
|
8
|
+
const LIMIT = Math.max(1, Math.min(8, cores - 1));
|
|
9
|
+
/** Largest job first, so that the smaller ones fill the other workers meanwhile. */
|
|
10
|
+
const queue = [];
|
|
11
|
+
/** How many encoder workers run: a process-wide pool, as each holds its own WASM memory and LIMIT bounds them all. */
|
|
12
|
+
let workers = 0;
|
|
13
|
+
/**
|
|
14
|
+
* One map as a KTX2 file of Basis UASTC. Each level encodes as `parts` strips of rows, by default one per worker, so
|
|
15
|
+
* that a map's top level, which holds three quarters of its texels, takes all workers; the strips' and levels' files
|
|
16
|
+
* are then joined. Takes about a second per million texels and worker.
|
|
17
|
+
*/
|
|
18
|
+
export async function encodeLayer({ levels, size, srgb }, parts = LIMIT) {
|
|
19
|
+
const files = await Promise.all(levels.map((data, m) => Promise.all(strips(data, size >> m, srgb, parts).map((job) => encodeJob(job).then(read)))));
|
|
20
|
+
const first = files[0]?.[0];
|
|
21
|
+
if (!first)
|
|
22
|
+
throw new Error("encodeImpostorAsync: a map has no mip levels");
|
|
23
|
+
// UASTC encodes each 4x4 block on its own, and a level's Zstandard data may be several frames, which decode as one:
|
|
24
|
+
// a level's strips, each a multiple of four rows high but the last, concatenate to data that decodes as the whole level's.
|
|
25
|
+
first.levels = files.map((parts) => {
|
|
26
|
+
const levels = parts.map((file) => {
|
|
27
|
+
const [level] = file.levels;
|
|
28
|
+
if (!level)
|
|
29
|
+
throw new Error("encodeImpostorAsync: the encoder wrote a file without levels");
|
|
30
|
+
return level;
|
|
31
|
+
});
|
|
32
|
+
const levelData = new Uint8Array(levels.reduce((sum, level) => sum + level.levelData.length, 0));
|
|
33
|
+
let offset = 0;
|
|
34
|
+
for (const level of levels) {
|
|
35
|
+
levelData.set(level.levelData, offset);
|
|
36
|
+
offset += level.levelData.length;
|
|
37
|
+
}
|
|
38
|
+
return { levelData, uncompressedByteLength: levels.reduce((sum, level) => sum + level.uncompressedByteLength, 0) };
|
|
39
|
+
});
|
|
40
|
+
first.pixelHeight = size;
|
|
41
|
+
first.levelCount = files.length;
|
|
42
|
+
return write(first);
|
|
43
|
+
}
|
|
44
|
+
/** A `size`² level's strips: at most `parts`, each a multiple of four rows high but perhaps the last. */
|
|
45
|
+
function strips(data, size, srgb, parts) {
|
|
46
|
+
const rows = 4 * Math.ceil(size / parts / 4);
|
|
47
|
+
const jobs = [];
|
|
48
|
+
// Sliced: each job owns its buffer, which moves to its worker.
|
|
49
|
+
for (let y = 0; y < size; y += rows) {
|
|
50
|
+
const height = Math.min(rows, size - y);
|
|
51
|
+
jobs.push({ data: data.slice(4 * size * y, 4 * size * (y + height)), width: size, height, srgb });
|
|
52
|
+
}
|
|
53
|
+
return jobs;
|
|
54
|
+
}
|
|
55
|
+
function encodeJob(job) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
queue.push({ job, resolve, reject });
|
|
58
|
+
queue.sort((a, b) => b.job.width * b.job.height - a.job.width * a.job.height);
|
|
59
|
+
if (workers < LIMIT)
|
|
60
|
+
void work();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** One worker, with its own encoder instance, that takes queued jobs until none is left and then ends. */
|
|
64
|
+
async function work() {
|
|
65
|
+
workers++;
|
|
66
|
+
let worker;
|
|
67
|
+
try {
|
|
68
|
+
for (let task = queue.shift(); task; task = queue.shift()) {
|
|
69
|
+
try {
|
|
70
|
+
worker ??= await start();
|
|
71
|
+
const reply = await run(worker, task.job);
|
|
72
|
+
if ("file" in reply)
|
|
73
|
+
task.resolve(reply.file);
|
|
74
|
+
else
|
|
75
|
+
task.reject(new Error(`encodeImpostorAsync: ${reply.error}`));
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
// The worker failed to load or crashed; the next job gets a fresh one.
|
|
79
|
+
task.reject(error);
|
|
80
|
+
worker?.terminate();
|
|
81
|
+
worker = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
worker?.terminate();
|
|
87
|
+
workers--;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function start() {
|
|
91
|
+
const { url } = await import("./worker.js");
|
|
92
|
+
return new Worker(url, { type: "module" });
|
|
93
|
+
}
|
|
94
|
+
/** `job` on `worker`; rejects when the worker fails rather than answers, as one that does not load does. */
|
|
95
|
+
function run(worker, job) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const settle = () => {
|
|
98
|
+
worker.removeEventListener("message", message);
|
|
99
|
+
worker.removeEventListener("error", error);
|
|
100
|
+
worker.removeEventListener("messageerror", error);
|
|
101
|
+
};
|
|
102
|
+
const message = (event) => {
|
|
103
|
+
settle();
|
|
104
|
+
resolve(event.data);
|
|
105
|
+
};
|
|
106
|
+
const error = (event) => {
|
|
107
|
+
settle();
|
|
108
|
+
const why = event instanceof ErrorEvent ? event.message : `${event.type} event`;
|
|
109
|
+
reject(new Error(`encodeImpostorAsync: the encoder worker failed (${why})`));
|
|
110
|
+
};
|
|
111
|
+
worker.addEventListener("message", message);
|
|
112
|
+
worker.addEventListener("error", error);
|
|
113
|
+
worker.addEventListener("messageerror", error);
|
|
114
|
+
worker.postMessage(job, [job.data.buffer]);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=encode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encode.js","sourceRoot":"","sources":["../../../src/impostor/ktx2/encode.ts"],"names":[],"mappings":"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"}
|