@woosh/meep-engine 3.14.0 → 3.14.2

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.
Files changed (220) hide show
  1. package/README.md +33 -64
  2. package/package.json +1 -1
  3. package/src/avif/native/DECISIONS.md +544 -536
  4. package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -1
  5. package/src/avif/native/heif/parse_avif_file.js +384 -383
  6. package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -1
  7. package/src/avif/native/heif/parse_image_grid.js +49 -48
  8. package/src/basis/BasisBitReader.d.ts +77 -0
  9. package/src/basis/BasisBitReader.d.ts.map +1 -0
  10. package/src/basis/BasisBitReader.js +231 -0
  11. package/src/basis/BasisHuffmanTable.d.ts +53 -0
  12. package/src/basis/BasisHuffmanTable.d.ts.map +1 -0
  13. package/src/basis/BasisHuffmanTable.js +263 -0
  14. package/src/basis/basis_read_huffman_table.d.ts +20 -0
  15. package/src/basis/basis_read_huffman_table.d.ts.map +1 -0
  16. package/src/basis/basis_read_huffman_table.js +187 -0
  17. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts +50 -0
  18. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts.map +1 -0
  19. package/src/basis/etc1s/Etc1sSelectorHistory.js +89 -0
  20. package/src/basis/etc1s/etc1s_block_colors.d.ts +14 -0
  21. package/src/basis/etc1s/etc1s_block_colors.d.ts.map +1 -0
  22. package/src/basis/etc1s/etc1s_block_colors.js +75 -0
  23. package/src/basis/etc1s/etc1s_decode_slice.d.ts +57 -0
  24. package/src/basis/etc1s/etc1s_decode_slice.d.ts.map +1 -0
  25. package/src/basis/etc1s/etc1s_decode_slice.js +258 -0
  26. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts +48 -0
  27. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts.map +1 -0
  28. package/src/basis/etc1s/etc1s_read_endpoint_codebook.js +111 -0
  29. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts +42 -0
  30. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts.map +1 -0
  31. package/src/basis/etc1s/etc1s_read_selector_codebook.js +127 -0
  32. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts +54 -0
  33. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts.map +1 -0
  34. package/src/basis/etc1s/etc1s_read_slice_tables.js +47 -0
  35. package/src/basis/transcode/build_range_plan.js +54 -0
  36. package/src/basis/transcode/etc1s_to_bc1.d.ts +24 -0
  37. package/src/basis/transcode/etc1s_to_bc1.d.ts.map +1 -0
  38. package/src/basis/transcode/etc1s_to_bc1.js +205 -0
  39. package/src/basis/transcode/etc1s_to_bc7.d.ts +30 -0
  40. package/src/basis/transcode/etc1s_to_bc7.d.ts.map +1 -0
  41. package/src/basis/transcode/etc1s_to_bc7.js +496 -0
  42. package/src/basis/transcode/fit_endpoints.d.ts +59 -0
  43. package/src/basis/transcode/fit_endpoints.d.ts.map +1 -0
  44. package/src/basis/transcode/fit_endpoints.js +226 -0
  45. package/src/{avif/native/isobmff → core/binary}/ByteCursor.d.ts +19 -6
  46. package/src/core/binary/ByteCursor.d.ts.map +1 -0
  47. package/src/{avif/native/isobmff → core/binary}/ByteCursor.js +41 -14
  48. package/src/engine/EngineHarness.js +1 -1
  49. package/src/engine/asset/codec/Codec.d.ts.map +1 -0
  50. package/src/engine/asset/codec/CodecWithFallback.d.ts.map +1 -0
  51. package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.js +2 -2
  52. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +4 -4
  53. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  54. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  55. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
  56. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +1 -1
  57. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
  58. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +1 -1
  59. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts +1 -1
  60. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts.map +1 -1
  61. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +1 -1
  62. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  63. package/src/engine/graphics/texture/atlas/TextureAtlas.js +13 -0
  64. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  65. package/src/engine/physics/broadphase/generate_pairs.js +7 -1
  66. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  67. package/src/ktx2/KTX2_IDENTIFIER.d.ts +14 -0
  68. package/src/ktx2/KTX2_IDENTIFIER.d.ts.map +1 -0
  69. package/src/ktx2/KTX2_IDENTIFIER.js +15 -0
  70. package/src/ktx2/KhrDfModel.d.ts +35 -0
  71. package/src/ktx2/KhrDfModel.d.ts.map +1 -0
  72. package/src/ktx2/KhrDfModel.js +49 -0
  73. package/src/ktx2/SupercompressionScheme.d.ts +16 -0
  74. package/src/ktx2/SupercompressionScheme.d.ts.map +1 -0
  75. package/src/ktx2/SupercompressionScheme.js +23 -0
  76. package/src/ktx2/ktx2_read.d.ts +71 -0
  77. package/src/ktx2/ktx2_read.d.ts.map +1 -0
  78. package/src/ktx2/ktx2_read.js +581 -0
  79. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts +27 -0
  80. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts.map +1 -0
  81. package/src/ktx2/ktx2_read_basis_lz_global_data.js +189 -0
  82. package/src/ktx2/vk_format_to_texture_format.d.ts +55 -0
  83. package/src/ktx2/vk_format_to_texture_format.d.ts.map +1 -0
  84. package/src/ktx2/vk_format_to_texture_format.js +290 -0
  85. package/src/shade/descriptor/GPUTextureUsage.d.ts +23 -0
  86. package/src/shade/descriptor/GPUTextureUsage.d.ts.map +1 -0
  87. package/src/shade/descriptor/GPUTextureUsage.js +24 -0
  88. package/src/shade/descriptor/WebGPUExtensionType.d.ts +3 -0
  89. package/src/shade/descriptor/WebGPUExtensionType.js +26 -0
  90. package/src/shade/descriptor/texture/TextureDescriptor.d.ts +2 -6
  91. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  92. package/src/shade/descriptor/texture/TextureDescriptor.js +24 -40
  93. package/src/shade/descriptor/texture/format/TextureFormat.d.ts +125 -0
  94. package/src/shade/descriptor/texture/format/TextureFormat.d.ts.map +1 -0
  95. package/src/shade/descriptor/texture/format/TextureFormat.js +146 -0
  96. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts +60 -0
  97. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts.map +1 -1
  98. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +102 -0
  99. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  100. package/src/shade/device/graph/TextureResourceDescriptor.js +160 -155
  101. package/src/shade/device/mock/SoftwareGPUQueue.d.ts +11 -4
  102. package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
  103. package/src/shade/device/mock/SoftwareGPUQueue.js +31 -37
  104. package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
  105. package/src/shade/device/mock/SoftwareGPUTexture.js +8 -4
  106. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -1
  107. package/src/shade/device/timing/profile/frame_graph_extract_topology.js +164 -174
  108. package/src/shade/playground/ground_seam/README.md +235 -0
  109. package/src/shade/playground/ground_seam/capture_scene_color.d.ts +45 -0
  110. package/src/shade/playground/ground_seam/capture_scene_color.d.ts.map +1 -0
  111. package/src/shade/playground/ground_seam/capture_scene_color.js +242 -0
  112. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts +11 -0
  113. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts.map +1 -0
  114. package/src/shade/playground/ground_seam/depth_step_across_seam.js +185 -0
  115. package/src/shade/playground/ground_seam/index.html +195 -0
  116. package/src/shade/playground/ground_seam/main.d.ts +2 -0
  117. package/src/shade/playground/ground_seam/main.d.ts.map +1 -0
  118. package/src/shade/playground/ground_seam/main.js +879 -0
  119. package/src/shade/playground/ground_seam/make_grid_texture.d.ts +29 -0
  120. package/src/shade/playground/ground_seam/make_grid_texture.d.ts.map +1 -0
  121. package/src/shade/playground/ground_seam/make_grid_texture.js +105 -0
  122. package/src/shade/playground/ground_seam/make_ground.d.ts +70 -0
  123. package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -0
  124. package/src/shade/playground/ground_seam/make_ground.js +161 -0
  125. package/src/shade/playground/ground_seam/measure_flicker.d.ts +71 -0
  126. package/src/shade/playground/ground_seam/measure_flicker.d.ts.map +1 -0
  127. package/src/shade/playground/ground_seam/measure_flicker.js +531 -0
  128. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  129. package/src/shade/renderer/Renderer.js +2519 -2511
  130. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  131. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +275 -274
  132. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  133. package/src/shade/renderer/light/GPULightCollection.js +323 -314
  134. package/src/shade/renderer/lightmap/GPULightMap.js +336 -336
  135. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  136. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +12 -2
  137. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  138. package/src/shade/renderer/material/standard/fragment_gbuffer.js +3 -1
  139. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  140. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  141. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +3 -1
  142. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  143. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  144. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.js +3 -1
  145. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  146. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.js +3 -1
  147. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts +28 -0
  148. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts.map +1 -0
  149. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.js +39 -0
  150. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts +45 -0
  151. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts.map +1 -1
  152. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.js +94 -61
  153. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts +24 -0
  154. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts.map +1 -0
  155. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.js +43 -0
  156. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +1462 -0
  157. package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
  158. package/src/shade/renderer/texture/TextureManager.js +20 -8
  159. package/src/shade/renderer/texture/TextureRole.d.ts +19 -0
  160. package/src/shade/renderer/texture/TextureRole.d.ts.map +1 -0
  161. package/src/shade/renderer/texture/TextureRole.js +26 -0
  162. package/src/shade/renderer/texture/TextureVariantSet.d.ts +71 -0
  163. package/src/shade/renderer/texture/TextureVariantSet.d.ts.map +1 -0
  164. package/src/shade/renderer/texture/TextureVariantSet.js +105 -0
  165. package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
  166. package/src/shade/renderer/texture/download_texture_data.js +22 -0
  167. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts +15 -0
  168. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts.map +1 -0
  169. package/src/shade/renderer/texture/format/gpu_texture_compression_support.js +50 -0
  170. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts +27 -0
  171. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts.map +1 -0
  172. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.js +65 -0
  173. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts +11 -0
  174. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -0
  175. package/src/shade/renderer/texture/format/infer_format_from_parameters.js +88 -0
  176. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +24 -0
  177. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -0
  178. package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +71 -0
  179. package/src/shade/renderer/texture/format/texture_format_preference.d.ts +22 -0
  180. package/src/shade/renderer/texture/format/texture_format_preference.d.ts.map +1 -0
  181. package/src/shade/renderer/texture/format/texture_format_preference.js +89 -0
  182. package/src/shade/renderer/texture/format/texture_variant_select.d.ts +24 -0
  183. package/src/shade/renderer/texture/format/texture_variant_select.d.ts.map +1 -0
  184. package/src/shade/renderer/texture/format/texture_variant_select.js +38 -0
  185. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts +9 -1
  186. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts.map +1 -1
  187. package/src/shade/renderer/texture/shade_texture_might_have_alpha.js +73 -8
  188. package/src/shade/renderer/texture/source/AlphaMode.d.ts +27 -0
  189. package/src/shade/renderer/texture/source/AlphaMode.d.ts.map +1 -0
  190. package/src/shade/renderer/texture/source/AlphaMode.js +52 -0
  191. package/src/shade/renderer/texture/source/ShadeImage.d.ts +33 -0
  192. package/src/shade/renderer/texture/source/ShadeImage.d.ts.map +1 -1
  193. package/src/shade/renderer/texture/source/ShadeImage.js +74 -0
  194. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts +78 -0
  195. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts.map +1 -0
  196. package/src/shade/renderer/texture/source/ShadeTexelData.js +158 -0
  197. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts +0 -10
  198. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts.map +1 -1
  199. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -175
  200. package/src/shade/renderer/texture/texture_write_level.d.ts +32 -0
  201. package/src/shade/renderer/texture/texture_write_level.d.ts.map +1 -0
  202. package/src/shade/renderer/texture/texture_write_level.js +77 -0
  203. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts +8 -1
  204. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
  205. package/src/shade/renderer/texture/texture_write_to_gpu.js +62 -37
  206. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts +8 -0
  207. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts.map +1 -1
  208. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +8 -0
  209. package/src/shade/util/texture_mip_extent.d.ts +49 -0
  210. package/src/shade/util/texture_mip_extent.d.ts.map +1 -0
  211. package/src/shade/util/texture_mip_extent.js +87 -0
  212. package/src/avif/native/isobmff/ByteCursor.d.ts.map +0 -1
  213. package/src/engine/asset/loaders/image/codec/Codec.d.ts.map +0 -1
  214. package/src/engine/asset/loaders/image/codec/CodecWithFallback.d.ts.map +0 -1
  215. package/src/shade/util/compute_max_mip_count.d.ts +0 -8
  216. package/src/shade/util/compute_max_mip_count.d.ts.map +0 -1
  217. package/src/shade/util/compute_max_mip_count.js +0 -27
  218. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.d.ts +0 -0
  219. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.js +0 -0
  220. /package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.d.ts +0 -0
@@ -1,314 +1,323 @@
1
- import { assert } from "../../../core/assert.js";
2
- import { ShadeGPUCommandContext } from "../../device/ShadeGPUCommandContext.js";
3
- import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
4
- import { GPUSceneShadowmapContext } from "../shadow/map/GPUSceneShadowmapContext.js";
5
- import { GPUTextureContext } from "../texture/GPUTextureContext.js";
6
- import { compute_max_mip_count } from "../../util/compute_max_mip_count.js";
7
- import { texture_write_to_gpu } from "../texture/texture_write_to_gpu.js";
8
- import { execute_filter_environment_map } from "./environment/execute_filter_environment_map.js";
9
- import { LIGHT_DATABASE_SPEC } from "./LIGHT_DATABASE_SPEC.js";
10
- import { light_record_directional } from "./model/io/light_record_directional.js";
11
- import { light_record_point } from "./model/io/light_record_point.js";
12
- import { light_record_spot } from "./model/io/light_record_spot.js";
13
-
14
- /**
15
- * Directional-light cap. Sized so the directional occupancy bitmap
16
- * fits in a single u32, which is what
17
- * {@link chunk_directional_lights_iteration_mask} reads. Writing past
18
- * key 31 would silently drop the light from iteration; {@link #build}
19
- * warns once per build when this happens.
20
- *
21
- * Point and spot lights have no analogous cap — their consumers walk
22
- * the full per-page bitmap, so any number of point/spot lights
23
- * iterate correctly (e.g. clustered rendering routinely deals in
24
- * hundreds).
25
- *
26
- * @type {number}
27
- */
28
- const MAX_DIRECTIONAL_LIGHTS = 32;
29
-
30
- export class GPULightCollection {
31
-
32
- /**
33
- * @type {LightCollection}
34
- */
35
- #source
36
-
37
- /**
38
- *
39
- * @returns {LightCollection}
40
- */
41
- get source() {
42
- return this.#source;
43
- }
44
-
45
- /**
46
- * @type {GPUDevice}
47
- */
48
- #device
49
-
50
- /**
51
- * Backing GPUDatabase for the per-type light tables (point, spot, directional)
52
- * and shadowmap regions. Layout is defined by {@link LIGHT_DATABASE_SPEC}.
53
- *
54
- * @type {GPUDatabase}
55
- */
56
- #database;
57
-
58
- /**
59
- * @returns {GPUDatabase}
60
- */
61
- get database() {
62
- return this.#database;
63
- }
64
-
65
- /**
66
- * The single GPU buffer that backs the database. Bind this as `array<u32>` in
67
- * shaders that need to read light records via the auto-generated
68
- * {@link GPUTypedTableDescriptor.chunk_read} helpers.
69
- *
70
- * @returns {GPUBuffer}
71
- */
72
- get buffer_data() {
73
- return this.#database.buffer;
74
- }
75
-
76
- /**
77
- * Per-scene shadow allocator + rasterizer, owned by this collection because the
78
- * shadow records live in the same database (shadow_point / shadow_spot /
79
- * shadow_directional tables) and the per-light `shadow_id` field is the index into
80
- * those tables. Lifecycle, update, and destruction are all chained off this object.
81
- * @type {GPUSceneShadowmapContext}
82
- */
83
- #shadow_context;
84
-
85
- /**
86
- * @returns {GPUSceneShadowmapContext}
87
- */
88
- get shadow_context() {
89
- return this.#shadow_context;
90
- }
91
-
92
- /**
93
- *
94
- * @type {number}
95
- */
96
- #committed_version = -1;
97
-
98
- /**
99
- * Per-type counts written in the previous {@link build} pass. Used to identify
100
- * the trailing slot range that must be removed to keep each table tightly packed.
101
- */
102
- #prev_point_count = 0;
103
- #prev_spot_count = 0;
104
- #prev_directional_count = 0;
105
-
106
- /**
107
- * Octahedral encoded texture, convolved
108
- * see {@link LightCollection.environment}
109
- * @type {GPUTextureContext}
110
- */
111
- #environment;
112
-
113
- /**
114
- * @type {ShadeTexture}
115
- */
116
- #environment_source;
117
-
118
-
119
- /**
120
- *
121
- * @returns {GPUTextureContext}
122
- */
123
- get environment() {
124
- return this.#environment;
125
- }
126
-
127
-
128
- get gpu_memory_usage() {
129
- return this.#environment.gpu_memory_usage
130
- + this.#database.gpu_memory_usage
131
- ;
132
- }
133
-
134
- /**
135
- *
136
- * @param {GraphicsContext} graphics
137
- * @param {GPUSceneContext} scene_ctx the GPU-side context for this scene; the shadow
138
- * context constructs its own ViewManager that needs to look up this same context
139
- * when materializing GPUViewContexts for shadow views.
140
- */
141
- constructor(graphics, scene_ctx) {
142
- assert.defined(graphics, 'graphics');
143
- assert.defined(scene_ctx, 'scene_ctx');
144
- assert.equal(scene_ctx.isGPUSceneContext, true, 'scene_ctx.isGPUSceneContext !== true');
145
-
146
- const scene = scene_ctx.scene;
147
- const device = graphics.device;
148
-
149
- this.#device = device;
150
- this.#source = scene.lights;
151
-
152
- this.#environment = new GPUTextureContext(this.#device);
153
- this.#environment.descriptor.label = "environment map";
154
- this.#environment.descriptor.format = "rgba16float";
155
- this.#environment.descriptor.usage |=
156
- GPUTextureUsage.COPY_DST // so we can write to it
157
- | GPUTextureUsage.STORAGE_BINDING // so we can convolve it in compute shader
158
- ;
159
-
160
- this.#database = new GPUDatabase({
161
- device,
162
- label: 'Light Collection / Database',
163
- definition: LIGHT_DATABASE_SPEC,
164
- });
165
-
166
- this.#shadow_context = new GPUSceneShadowmapContext(graphics, scene_ctx, this);
167
- }
168
-
169
- /**
170
- *
171
- * @param {GraphicsContext} ctx
172
- */
173
- #update_environment(ctx) {
174
- const source_env = this.#source.environment;
175
-
176
- if (this.#environment_source === source_env) {
177
- // assume up-to-date
178
- return;
179
- }
180
-
181
- this.#environment_source = source_env;
182
-
183
- const gpu_ctx = this.#environment;
184
-
185
- const source_image = source_env.image;
186
- gpu_ctx.resize(source_image.width, source_image.height);
187
- gpu_ctx.descriptor.mipLevelCount = compute_max_mip_count(source_image.width, source_image.height);
188
-
189
- gpu_ctx.allocate();
190
-
191
- if (
192
- source_image.source instanceof ImageBitmap
193
- && (gpu_ctx.descriptor.usage & GPUTextureUsage.RENDER_ATTACHMENT) === 0
194
- ) {
195
- // need RENDER_ATTACHMENT to use GPUQueue.copyExternalImageToTexture API
196
- // update descriptor and re-allocate texture
197
- gpu_ctx.descriptor.usage |= GPUTextureUsage.RENDER_ATTACHMENT;
198
- gpu_ctx.allocate(false);
199
- }
200
-
201
- texture_write_to_gpu(source_image, gpu_ctx.gpu_texture, this.#device.queue);
202
-
203
- // convolve
204
- const cmd = ShadeGPUCommandContext.create(ctx);
205
-
206
- execute_filter_environment_map(gpu_ctx, cmd);
207
-
208
- cmd.finish();
209
- }
210
-
211
- /**
212
- *
213
- * @param {GraphicsContext} ctx
214
- */
215
- update(ctx) {
216
- assert.defined(ctx, 'ctx');
217
-
218
- this.#update_environment(ctx);
219
-
220
- // Reconcile shadow allocations against the current scene every frame, even when
221
- // {@link LightCollection.version} hasn't moved. Shadow allocations can shift on
222
- // changes that don't bump version (e.g. flipping `light.casts_shadow`), and the
223
- // `shadow_id` we stamp into each light record depends on this allocation. When
224
- // process_lights touches anything we mark the source dirty so the build below
225
- // re-publishes those records.
226
- if (this.#shadow_context.process_lights()) {
227
- this.#source.needsUpdate = true;
228
- }
229
-
230
- if (this.#committed_version === this.#source.version) {
231
- return;
232
- }
233
-
234
- const cmd = ShadeGPUCommandContext.create(ctx, 'GPULightCollection/build');
235
-
236
- this.#build(cmd);
237
-
238
- cmd.finish();
239
- }
240
-
241
- /**
242
- * Marshal source lights into the per-type database tables, keeping each table
243
- * tightly packed in the index range [0, type_count).
244
- *
245
- * @param {ShadeGPUCommandContext} cmd
246
- */
247
- #build(cmd) {
248
- const lights = this.#source.elements;
249
-
250
- const table_point = this.#database.get('light_point');
251
- const table_spot = this.#database.get('light_spot');
252
- const table_directional = this.#database.get('light_directional');
253
-
254
- let point_count = 0;
255
- let spot_count = 0;
256
- let directional_count = 0;
257
-
258
- // Directional only — silently dropping a directional light
259
- // would surface as a missing visual; flagging keeps consumers
260
- // iterating only the first bitmap word correct for whatever
261
- // did fit. Point and spot have no cap.
262
- let directional_overflow_warned = false;
263
-
264
- for (let i = 0; i < lights.length; i++) {
265
- const light = lights[i];
266
-
267
- if (light.isPointLight === true) {
268
- table_point.set(point_count, light_record_point(light));
269
- point_count++;
270
- } else if (light.isDirectionalLight === true) {
271
- if (directional_count >= MAX_DIRECTIONAL_LIGHTS) {
272
- if (!directional_overflow_warned) {
273
- console.warn(
274
- `GPULightCollection: directional light count exceeds MAX_DIRECTIONAL_LIGHTS (${MAX_DIRECTIONAL_LIGHTS}); extras will not be written to the database.`
275
- );
276
- directional_overflow_warned = true;
277
- }
278
- continue;
279
- }
280
- table_directional.set(directional_count, light_record_directional(light));
281
- directional_count++;
282
- } else if (light.isSpotLight === true) {
283
- table_spot.set(spot_count, light_record_spot(light));
284
- spot_count++;
285
- }
286
- // unrecognized light kinds are silently dropped
287
- }
288
-
289
- // trim trailing slots from previous build to keep each table tightly packed
290
- for (let i = point_count; i < this.#prev_point_count; i++) {
291
- table_point.remove(i);
292
- }
293
- for (let i = spot_count; i < this.#prev_spot_count; i++) {
294
- table_spot.remove(i);
295
- }
296
- for (let i = directional_count; i < this.#prev_directional_count; i++) {
297
- table_directional.remove(i);
298
- }
299
-
300
- this.#prev_point_count = point_count;
301
- this.#prev_spot_count = spot_count;
302
- this.#prev_directional_count = directional_count;
303
-
304
- this.#database.update(cmd);
305
-
306
- this.#committed_version = this.#source.version;
307
- }
308
-
309
- destroy() {
310
- this.#shadow_context.destroy();
311
- this.#database.destroy();
312
- this.#environment.destroy();
313
- }
314
- }
1
+ import { assert } from "../../../core/assert.js";
2
+ import { ShadeGPUCommandContext } from "../../device/ShadeGPUCommandContext.js";
3
+ import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
4
+ import { GPUSceneShadowmapContext } from "../shadow/map/GPUSceneShadowmapContext.js";
5
+ import { GPUTextureContext } from "../texture/GPUTextureContext.js";
6
+ import { texture_mip_level_count } from "../../util/texture_mip_extent.js";
7
+ import { texture_write_to_gpu } from "../texture/texture_write_to_gpu.js";
8
+ import { execute_filter_environment_map } from "./environment/execute_filter_environment_map.js";
9
+ import { LIGHT_DATABASE_SPEC } from "./LIGHT_DATABASE_SPEC.js";
10
+ import { light_record_directional } from "./model/io/light_record_directional.js";
11
+ import { light_record_point } from "./model/io/light_record_point.js";
12
+ import { light_record_spot } from "./model/io/light_record_spot.js";
13
+
14
+ /**
15
+ * Directional-light cap. Sized so the directional occupancy bitmap
16
+ * fits in a single u32, which is what
17
+ * {@link chunk_directional_lights_iteration_mask} reads. Writing past
18
+ * key 31 would silently drop the light from iteration; {@link #build}
19
+ * warns once per build when this happens.
20
+ *
21
+ * Point and spot lights have no analogous cap — their consumers walk
22
+ * the full per-page bitmap, so any number of point/spot lights
23
+ * iterate correctly (e.g. clustered rendering routinely deals in
24
+ * hundreds).
25
+ *
26
+ * @type {number}
27
+ */
28
+ const MAX_DIRECTIONAL_LIGHTS = 32;
29
+
30
+ export class GPULightCollection {
31
+
32
+ /**
33
+ * @type {LightCollection}
34
+ */
35
+ #source
36
+
37
+ /**
38
+ *
39
+ * @returns {LightCollection}
40
+ */
41
+ get source() {
42
+ return this.#source;
43
+ }
44
+
45
+ /**
46
+ * @type {GPUDevice}
47
+ */
48
+ #device
49
+
50
+ /**
51
+ * Backing GPUDatabase for the per-type light tables (point, spot, directional)
52
+ * and shadowmap regions. Layout is defined by {@link LIGHT_DATABASE_SPEC}.
53
+ *
54
+ * @type {GPUDatabase}
55
+ */
56
+ #database;
57
+
58
+ /**
59
+ * @returns {GPUDatabase}
60
+ */
61
+ get database() {
62
+ return this.#database;
63
+ }
64
+
65
+ /**
66
+ * The single GPU buffer that backs the database. Bind this as `array<u32>` in
67
+ * shaders that need to read light records via the auto-generated
68
+ * {@link GPUTypedTableDescriptor.chunk_read} helpers.
69
+ *
70
+ * @returns {GPUBuffer}
71
+ */
72
+ get buffer_data() {
73
+ return this.#database.buffer;
74
+ }
75
+
76
+ /**
77
+ * Per-scene shadow allocator + rasterizer, owned by this collection because the
78
+ * shadow records live in the same database (shadow_point / shadow_spot /
79
+ * shadow_directional tables) and the per-light `shadow_id` field is the index into
80
+ * those tables. Lifecycle, update, and destruction are all chained off this object.
81
+ * @type {GPUSceneShadowmapContext}
82
+ */
83
+ #shadow_context;
84
+
85
+ /**
86
+ * @returns {GPUSceneShadowmapContext}
87
+ */
88
+ get shadow_context() {
89
+ return this.#shadow_context;
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @type {number}
95
+ */
96
+ #committed_version = -1;
97
+
98
+ /**
99
+ * Per-type counts written in the previous {@link build} pass. Used to identify
100
+ * the trailing slot range that must be removed to keep each table tightly packed.
101
+ */
102
+ #prev_point_count = 0;
103
+ #prev_spot_count = 0;
104
+ #prev_directional_count = 0;
105
+
106
+ /**
107
+ * Octahedral encoded texture, convolved
108
+ * see {@link LightCollection.environment}
109
+ * @type {GPUTextureContext}
110
+ */
111
+ #environment;
112
+
113
+ /**
114
+ * @type {ShadeTexture}
115
+ */
116
+ #environment_source;
117
+
118
+
119
+ /**
120
+ *
121
+ * @returns {GPUTextureContext}
122
+ */
123
+ get environment() {
124
+ return this.#environment;
125
+ }
126
+
127
+
128
+ get gpu_memory_usage() {
129
+ return this.#environment.gpu_memory_usage
130
+ + this.#database.gpu_memory_usage
131
+ ;
132
+ }
133
+
134
+ /**
135
+ *
136
+ * @param {GraphicsContext} graphics
137
+ * @param {GPUSceneContext} scene_ctx the GPU-side context for this scene; the shadow
138
+ * context constructs its own ViewManager that needs to look up this same context
139
+ * when materializing GPUViewContexts for shadow views.
140
+ */
141
+ constructor(graphics, scene_ctx) {
142
+ assert.defined(graphics, 'graphics');
143
+ assert.defined(scene_ctx, 'scene_ctx');
144
+ assert.equal(scene_ctx.isGPUSceneContext, true, 'scene_ctx.isGPUSceneContext !== true');
145
+
146
+ const scene = scene_ctx.scene;
147
+ const device = graphics.device;
148
+
149
+ this.#device = device;
150
+ this.#source = scene.lights;
151
+
152
+ this.#environment = new GPUTextureContext(this.#device);
153
+ this.#environment.descriptor.label = "environment map";
154
+ this.#environment.descriptor.format = "rgba16float";
155
+ this.#environment.descriptor.usage |=
156
+ GPUTextureUsage.COPY_DST // so we can write to it
157
+ | GPUTextureUsage.STORAGE_BINDING // so we can convolve it in compute shader
158
+ ;
159
+
160
+ this.#database = new GPUDatabase({
161
+ device,
162
+ label: 'Light Collection / Database',
163
+ definition: LIGHT_DATABASE_SPEC,
164
+ });
165
+
166
+ this.#shadow_context = new GPUSceneShadowmapContext(graphics, scene_ctx, this);
167
+ }
168
+
169
+ /**
170
+ *
171
+ * @param {GraphicsContext} ctx
172
+ */
173
+ #update_environment(ctx) {
174
+ const source_env = this.#source.environment;
175
+
176
+ if (this.#environment_source === source_env) {
177
+ // assume up-to-date
178
+ return;
179
+ }
180
+
181
+ this.#environment_source = source_env;
182
+
183
+ const gpu_ctx = this.#environment;
184
+
185
+ const source_image = source_env.image;
186
+ gpu_ctx.resize(source_image.width, source_image.height);
187
+ /*
188
+ The environment map is equirectangular and this context is built 2D a few lines up — the
189
+ descriptor keeps the default dimension and `resize` above only takes two axes. Asked of the
190
+ descriptor rather than assumed, so the count follows if that ever stops being true.
191
+ */
192
+ const gpu_size = gpu_ctx.descriptor.size;
193
+
194
+ gpu_ctx.descriptor.mipLevelCount = texture_mip_level_count(
195
+ gpu_size.width, gpu_size.height, gpu_size.depthOrArrayLayers, gpu_ctx.descriptor.dimension
196
+ );
197
+
198
+ gpu_ctx.allocate();
199
+
200
+ if (
201
+ source_image.source instanceof ImageBitmap
202
+ && (gpu_ctx.descriptor.usage & GPUTextureUsage.RENDER_ATTACHMENT) === 0
203
+ ) {
204
+ // need RENDER_ATTACHMENT to use GPUQueue.copyExternalImageToTexture API
205
+ // update descriptor and re-allocate texture
206
+ gpu_ctx.descriptor.usage |= GPUTextureUsage.RENDER_ATTACHMENT;
207
+ gpu_ctx.allocate(false);
208
+ }
209
+
210
+ texture_write_to_gpu(source_image, gpu_ctx.gpu_texture, this.#device.queue, source_image.level_count);
211
+
212
+ // convolve
213
+ const cmd = ShadeGPUCommandContext.create(ctx);
214
+
215
+ execute_filter_environment_map(gpu_ctx, cmd);
216
+
217
+ cmd.finish();
218
+ }
219
+
220
+ /**
221
+ *
222
+ * @param {GraphicsContext} ctx
223
+ */
224
+ update(ctx) {
225
+ assert.defined(ctx, 'ctx');
226
+
227
+ this.#update_environment(ctx);
228
+
229
+ // Reconcile shadow allocations against the current scene every frame, even when
230
+ // {@link LightCollection.version} hasn't moved. Shadow allocations can shift on
231
+ // changes that don't bump version (e.g. flipping `light.casts_shadow`), and the
232
+ // `shadow_id` we stamp into each light record depends on this allocation. When
233
+ // process_lights touches anything we mark the source dirty so the build below
234
+ // re-publishes those records.
235
+ if (this.#shadow_context.process_lights()) {
236
+ this.#source.needsUpdate = true;
237
+ }
238
+
239
+ if (this.#committed_version === this.#source.version) {
240
+ return;
241
+ }
242
+
243
+ const cmd = ShadeGPUCommandContext.create(ctx, 'GPULightCollection/build');
244
+
245
+ this.#build(cmd);
246
+
247
+ cmd.finish();
248
+ }
249
+
250
+ /**
251
+ * Marshal source lights into the per-type database tables, keeping each table
252
+ * tightly packed in the index range [0, type_count).
253
+ *
254
+ * @param {ShadeGPUCommandContext} cmd
255
+ */
256
+ #build(cmd) {
257
+ const lights = this.#source.elements;
258
+
259
+ const table_point = this.#database.get('light_point');
260
+ const table_spot = this.#database.get('light_spot');
261
+ const table_directional = this.#database.get('light_directional');
262
+
263
+ let point_count = 0;
264
+ let spot_count = 0;
265
+ let directional_count = 0;
266
+
267
+ // Directional only silently dropping a directional light
268
+ // would surface as a missing visual; flagging keeps consumers
269
+ // iterating only the first bitmap word correct for whatever
270
+ // did fit. Point and spot have no cap.
271
+ let directional_overflow_warned = false;
272
+
273
+ for (let i = 0; i < lights.length; i++) {
274
+ const light = lights[i];
275
+
276
+ if (light.isPointLight === true) {
277
+ table_point.set(point_count, light_record_point(light));
278
+ point_count++;
279
+ } else if (light.isDirectionalLight === true) {
280
+ if (directional_count >= MAX_DIRECTIONAL_LIGHTS) {
281
+ if (!directional_overflow_warned) {
282
+ console.warn(
283
+ `GPULightCollection: directional light count exceeds MAX_DIRECTIONAL_LIGHTS (${MAX_DIRECTIONAL_LIGHTS}); extras will not be written to the database.`
284
+ );
285
+ directional_overflow_warned = true;
286
+ }
287
+ continue;
288
+ }
289
+ table_directional.set(directional_count, light_record_directional(light));
290
+ directional_count++;
291
+ } else if (light.isSpotLight === true) {
292
+ table_spot.set(spot_count, light_record_spot(light));
293
+ spot_count++;
294
+ }
295
+ // unrecognized light kinds are silently dropped
296
+ }
297
+
298
+ // trim trailing slots from previous build to keep each table tightly packed
299
+ for (let i = point_count; i < this.#prev_point_count; i++) {
300
+ table_point.remove(i);
301
+ }
302
+ for (let i = spot_count; i < this.#prev_spot_count; i++) {
303
+ table_spot.remove(i);
304
+ }
305
+ for (let i = directional_count; i < this.#prev_directional_count; i++) {
306
+ table_directional.remove(i);
307
+ }
308
+
309
+ this.#prev_point_count = point_count;
310
+ this.#prev_spot_count = spot_count;
311
+ this.#prev_directional_count = directional_count;
312
+
313
+ this.#database.update(cmd);
314
+
315
+ this.#committed_version = this.#source.version;
316
+ }
317
+
318
+ destroy() {
319
+ this.#shadow_context.destroy();
320
+ this.#database.destroy();
321
+ this.#environment.destroy();
322
+ }
323
+ }