@forgeax/engine-render 0.1.28 → 0.1.29

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 (642) hide show
  1. package/README.md +627 -124
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/dynamic-geometry-host.d.ts +21 -0
  5. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  7. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +3 -1
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  11. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  12. package/dist/assembly/host-contract.d.ts +8 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +7 -0
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material-shader-policy.d.ts +3 -1
  17. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  18. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  19. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  20. package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
  21. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  22. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  23. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  24. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  25. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  26. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  27. package/dist/assembly/renderer-helpers.d.ts +3 -0
  28. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  29. package/dist/assembly/renderer-inspection.d.ts +4 -0
  30. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  31. package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
  32. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  33. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  34. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  35. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  36. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  37. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  38. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  41. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  42. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +7 -3
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  46. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  47. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  48. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  49. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  50. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  51. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  52. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  53. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  54. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  55. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  56. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  57. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  58. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  59. package/dist/authoring.mjs +2 -2
  60. package/dist/{chunk-JAASCMXA.mjs → chunk-33XZFTQU.mjs} +245 -39
  61. package/dist/chunk-33XZFTQU.mjs.map +1 -0
  62. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  63. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  64. package/dist/{chunk-J52NMQKR.mjs → chunk-BQVQOQJH.mjs} +1086 -838
  65. package/dist/chunk-BQVQOQJH.mjs.map +1 -0
  66. package/dist/{chunk-IQMKJLNU.mjs → chunk-BTWH7BP4.mjs} +386 -17
  67. package/dist/chunk-BTWH7BP4.mjs.map +1 -0
  68. package/dist/{chunk-MBU4ZVE7.mjs → chunk-FUODTTIA.mjs} +3921 -671
  69. package/dist/chunk-FUODTTIA.mjs.map +1 -0
  70. package/dist/{chunk-MYJ5RPJO.mjs → chunk-JQTSEI3Z.mjs} +3 -3
  71. package/dist/{chunk-MYJ5RPJO.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
  72. package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
  73. package/dist/chunk-NICXSHAT.mjs.map +1 -0
  74. package/dist/{chunk-J6KACNOH.mjs → chunk-NRNXBLIJ.mjs} +577 -7
  75. package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
  76. package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
  77. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  78. package/dist/{chunk-VSL23LZE.mjs → chunk-S4DNKQYQ.mjs} +1117 -445
  79. package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
  80. package/dist/components/camera.d.ts +62 -2
  81. package/dist/components/camera.d.ts.map +1 -1
  82. package/dist/components/index.d.ts +1 -0
  83. package/dist/components/index.d.ts.map +1 -1
  84. package/dist/components/instances.d.ts +6 -20
  85. package/dist/components/instances.d.ts.map +1 -1
  86. package/dist/components/scene-instance.d.ts +2 -1
  87. package/dist/components/scene-instance.d.ts.map +1 -1
  88. package/dist/components/screen-space-reflection.d.ts +14 -0
  89. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  90. package/dist/construct-renderer.mjs +12888 -7025
  91. package/dist/construct-renderer.mjs.map +1 -1
  92. package/dist/device/gpu-residency.d.ts +1 -12
  93. package/dist/device/gpu-residency.d.ts.map +1 -1
  94. package/dist/environment/background.d.ts +6 -0
  95. package/dist/environment/background.d.ts.map +1 -0
  96. package/dist/errors/gpu-driven.d.ts +6 -3
  97. package/dist/errors/gpu-driven.d.ts.map +1 -1
  98. package/dist/errors/render.d.ts +7 -4
  99. package/dist/errors/render.d.ts.map +1 -1
  100. package/dist/extract/camera.d.ts.map +1 -1
  101. package/dist/extract/gpu-driven.d.ts +33 -3
  102. package/dist/extract/gpu-driven.d.ts.map +1 -1
  103. package/dist/features/host.d.ts +23 -1
  104. package/dist/features/host.d.ts.map +1 -1
  105. package/dist/features/noise-texture.d.ts +17 -0
  106. package/dist/features/noise-texture.d.ts.map +1 -0
  107. package/dist/features/plan.d.ts +83 -2
  108. package/dist/features/plan.d.ts.map +1 -1
  109. package/dist/features/prepared-gpu-work.d.ts +37 -4
  110. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  111. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  112. package/dist/features/prepared-graphics.d.ts +5 -0
  113. package/dist/features/prepared-graphics.d.ts.map +1 -1
  114. package/dist/features/render-graph-compute.d.ts +5 -3
  115. package/dist/features/render-graph-compute.d.ts.map +1 -1
  116. package/dist/features/render-graph-contribution.d.ts +11 -3
  117. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  118. package/dist/features/render-graph-raster.d.ts +19 -3
  119. package/dist/features/render-graph-raster.d.ts.map +1 -1
  120. package/dist/features/types.d.ts +11 -0
  121. package/dist/features/types.d.ts.map +1 -1
  122. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  123. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  124. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  125. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  126. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  127. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  128. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  129. package/dist/gpu-driven/production-raster.d.ts +144 -23
  130. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  131. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  132. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  133. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  134. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  135. package/dist/gpu-scene-schema.d.ts +2 -8
  136. package/dist/gpu-scene-schema.d.ts.map +1 -1
  137. package/dist/gpu-scene.d.ts +14 -0
  138. package/dist/gpu-scene.d.ts.map +1 -1
  139. package/dist/gpu-texture-usage.d.ts +1 -0
  140. package/dist/gpu-texture-usage.d.ts.map +1 -1
  141. package/dist/hdrp-buffers.d.ts +6 -0
  142. package/dist/hdrp-buffers.d.ts.map +1 -1
  143. package/dist/ibl/frame-resources.d.ts +8 -0
  144. package/dist/ibl/frame-resources.d.ts.map +1 -0
  145. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  146. package/dist/index.d.ts +18 -8
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.mjs +8 -8
  149. package/dist/inspection-types.d.ts +164 -0
  150. package/dist/inspection-types.d.ts.map +1 -1
  151. package/dist/instances-derived-bounds.d.ts +11 -0
  152. package/dist/instances-derived-bounds.d.ts.map +1 -1
  153. package/dist/instances.d.ts +89 -44
  154. package/dist/instances.d.ts.map +1 -1
  155. package/dist/internal.d.ts +3 -0
  156. package/dist/internal.d.ts.map +1 -1
  157. package/dist/internal.mjs +117 -9
  158. package/dist/internal.mjs.map +1 -1
  159. package/dist/lifecycle.d.ts +2 -1
  160. package/dist/lifecycle.d.ts.map +1 -1
  161. package/dist/material-row.d.ts +5 -0
  162. package/dist/material-row.d.ts.map +1 -0
  163. package/dist/materials.d.ts +15 -0
  164. package/dist/materials.d.ts.map +1 -1
  165. package/dist/pbr-pipeline.d.ts +21 -5
  166. package/dist/pbr-pipeline.d.ts.map +1 -1
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  169. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  170. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  171. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  172. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  173. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  174. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  175. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  176. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  177. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  178. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  179. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  180. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  181. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  182. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  183. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  184. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  185. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  186. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  187. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  188. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  189. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  190. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  191. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  192. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  193. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  194. package/dist/pipeline/standard-output/types.d.ts +39 -0
  195. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  196. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  197. package/dist/pipeline/standard-post.d.ts +2 -2
  198. package/dist/pipeline/standard-post.d.ts.map +1 -1
  199. package/dist/pipeline-builder.d.ts +2 -1
  200. package/dist/pipeline-builder.d.ts.map +1 -1
  201. package/dist/pipeline-spec-types.d.ts +4 -0
  202. package/dist/pipeline-spec-types.d.ts.map +1 -1
  203. package/dist/pipeline-spec.d.ts +1 -9
  204. package/dist/pipeline-spec.d.ts.map +1 -1
  205. package/dist/points-lines/standard-owner.d.ts +1 -1
  206. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  207. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  208. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  209. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  210. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  211. package/dist/record/frame-lighting.d.ts +3 -3
  212. package/dist/record/frame-lighting.d.ts.map +1 -1
  213. package/dist/record/frame-snapshot.d.ts +106 -5
  214. package/dist/record/frame-snapshot.d.ts.map +1 -1
  215. package/dist/record/frame-targets.d.ts.map +1 -1
  216. package/dist/record/frame.d.ts +39 -4
  217. package/dist/record/frame.d.ts.map +1 -1
  218. package/dist/record/main-pass-geometry.d.ts +7 -8
  219. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  220. package/dist/record/main-pass-material.d.ts +38 -1
  221. package/dist/record/main-pass-material.d.ts.map +1 -1
  222. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  223. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  224. package/dist/record/main-pass.d.ts +12 -2
  225. package/dist/record/main-pass.d.ts.map +1 -1
  226. package/dist/record/mesh-ssbo.d.ts +15 -6
  227. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  228. package/dist/record/prepared-material-bindings.d.ts +19 -0
  229. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  230. package/dist/record/recovery-pipeline.d.ts +2 -9
  231. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  232. package/dist/record/render-context.d.ts +74 -26
  233. package/dist/record/render-context.d.ts.map +1 -1
  234. package/dist/record/shadow-pass.d.ts +62 -7
  235. package/dist/record/shadow-pass.d.ts.map +1 -1
  236. package/dist/record/skybox-post-pass.d.ts +1 -1
  237. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  238. package/dist/record/typed-frame-graph.d.ts +35 -7
  239. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  240. package/dist/record/view-ubo.d.ts +1 -0
  241. package/dist/record/view-ubo.d.ts.map +1 -1
  242. package/dist/recovery/render-system-candidate.d.ts +10 -2
  243. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  244. package/dist/recovery/render-system-roots.d.ts +11 -0
  245. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  246. package/dist/recovery/types.d.ts +76 -0
  247. package/dist/recovery/types.d.ts.map +1 -0
  248. package/dist/reflection/record-owner.d.ts +0 -2
  249. package/dist/reflection/record-owner.d.ts.map +1 -1
  250. package/dist/render-contract.d.ts +173 -30
  251. package/dist/render-contract.d.ts.map +1 -1
  252. package/dist/render-graph-primitives.d.ts +1 -0
  253. package/dist/render-graph-primitives.d.ts.map +1 -1
  254. package/dist/render-pipeline.d.ts +64 -5
  255. package/dist/render-pipeline.d.ts.map +1 -1
  256. package/dist/render-system-extract-tail.d.ts +7 -5
  257. package/dist/render-system-extract-tail.d.ts.map +1 -1
  258. package/dist/render-system-extract.d.ts +101 -41
  259. package/dist/render-system-extract.d.ts.map +1 -1
  260. package/dist/render-system-projections.d.ts +22 -0
  261. package/dist/render-system-projections.d.ts.map +1 -0
  262. package/dist/render-system.d.ts +27 -77
  263. package/dist/render-system.d.ts.map +1 -1
  264. package/dist/scene/render-scene-types.d.ts +14 -7
  265. package/dist/scene/render-scene-types.d.ts.map +1 -1
  266. package/dist/scene/render-scene.d.ts +29 -11
  267. package/dist/scene/render-scene.d.ts.map +1 -1
  268. package/dist/scene/shadow-visibility.d.ts +5 -0
  269. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  270. package/dist/ssr/admission.d.ts +70 -1
  271. package/dist/ssr/admission.d.ts.map +1 -1
  272. package/dist/ssr/compose.d.ts +13 -0
  273. package/dist/ssr/compose.d.ts.map +1 -0
  274. package/dist/ssr/errors.d.ts +35 -0
  275. package/dist/ssr/errors.d.ts.map +1 -1
  276. package/dist/ssr/graph.d.ts +60 -0
  277. package/dist/ssr/graph.d.ts.map +1 -0
  278. package/dist/ssr/history.d.ts +97 -0
  279. package/dist/ssr/history.d.ts.map +1 -0
  280. package/dist/ssr/hiz.d.ts +37 -0
  281. package/dist/ssr/hiz.d.ts.map +1 -0
  282. package/dist/ssr/inspection.d.ts +42 -0
  283. package/dist/ssr/inspection.d.ts.map +1 -0
  284. package/dist/ssr/resources.d.ts +58 -0
  285. package/dist/ssr/resources.d.ts.map +1 -0
  286. package/dist/ssr/temporal.d.ts +38 -0
  287. package/dist/ssr/temporal.d.ts.map +1 -0
  288. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  289. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  290. package/dist/systems/skin-palette-types.d.ts +15 -0
  291. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  292. package/dist/systems/transparent-dispatch.d.ts +9 -0
  293. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  294. package/dist/targets/material-source.d.ts +7 -0
  295. package/dist/targets/material-source.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts +7 -0
  297. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  298. package/dist/temporal/gpu.d.ts +8 -0
  299. package/dist/temporal/gpu.d.ts.map +1 -1
  300. package/dist/temporal/history.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +6 -6
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts +2 -1
  304. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  305. package/dist/temporal/temporal-view.d.ts +2 -0
  306. package/dist/temporal/temporal-view.d.ts.map +1 -1
  307. package/dist/typed-render-graph-primitives.d.ts +35 -1
  308. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  309. package/dist/typed-shadow-passes.d.ts +3 -1
  310. package/dist/typed-shadow-passes.d.ts.map +1 -1
  311. package/dist/volume/temporal.d.ts +6 -0
  312. package/dist/volume/temporal.d.ts.map +1 -1
  313. package/package.json +21 -20
  314. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  315. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  316. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  317. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  318. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  319. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  320. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  321. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  322. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  323. package/src/__tests__/factory-contract.integration.test.ts +67 -8
  324. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  325. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  326. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  327. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  328. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  329. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  330. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  331. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  332. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  333. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
  334. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  335. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  336. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
  337. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
  338. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
  339. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  340. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  341. package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
  342. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  343. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  344. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  345. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  346. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  347. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  348. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  349. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  350. package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
  351. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
  352. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  353. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  354. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  355. package/src/__tests__/gpu-scene.unit.test.ts +559 -33
  356. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  357. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  358. package/src/__tests__/instances-store.unit.test.ts +242 -39
  359. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  360. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  361. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  362. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  363. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  364. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  365. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  366. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  367. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  368. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  369. package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
  370. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  371. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  372. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  373. package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
  374. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  375. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  376. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  378. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
  379. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  380. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  381. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  382. package/src/__tests__/public-surface.test-d.ts +3 -0
  383. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  384. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
  385. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
  386. package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
  387. package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
  388. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  389. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  390. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  391. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  392. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  393. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  394. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  395. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  396. package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
  397. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  398. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  399. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  400. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  401. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +60 -0
  402. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  403. package/src/__tests__/shader-manifest-fixture.ts +39 -0
  404. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  405. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  406. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  407. package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
  408. package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
  409. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  410. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  411. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  412. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  413. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
  414. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
  415. package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
  416. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  417. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  418. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  419. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  420. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  421. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  422. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  423. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  424. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  425. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  426. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  427. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  428. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  429. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  430. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  431. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  432. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  433. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  434. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  435. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  436. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  437. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  438. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
  439. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  440. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  441. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  442. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  443. package/src/__tests__/standard-output.browser.test.ts +15 -0
  444. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  445. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
  446. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  447. package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
  448. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  449. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  450. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  451. package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
  452. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  453. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
  454. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  455. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  456. package/src/__tests__/taa-stability-feedback.ts +341 -0
  457. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  458. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  459. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  460. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  461. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  462. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  463. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  464. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  465. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  466. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  467. package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
  468. package/src/assembly/dynamic-geometry-host.ts +48 -0
  469. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  470. package/src/assembly/factory.ts +4 -0
  471. package/src/assembly/gpu-driven-owner.ts +29 -0
  472. package/src/assembly/host-contract.ts +10 -0
  473. package/src/assembly/material/assembly.ts +38 -0
  474. package/src/assembly/material-shader-policy.ts +71 -28
  475. package/src/assembly/recovery/failure-location.ts +62 -0
  476. package/src/assembly/recovery/renderer-recover.ts +19 -17
  477. package/src/assembly/renderer-facade.ts +12 -0
  478. package/src/assembly/renderer-feature-inspection.ts +13 -0
  479. package/src/assembly/renderer-frame-transaction.ts +63 -0
  480. package/src/assembly/renderer-helpers.ts +26 -0
  481. package/src/assembly/renderer-inspection.ts +6 -0
  482. package/src/assembly/shader-prewarm-policy.ts +32 -0
  483. package/src/assembly/skin-palette-owner.ts +21 -0
  484. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  485. package/src/assembly/webgpu-device-loss.ts +75 -0
  486. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  487. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  488. package/src/assembly/webgpu-ready.ts +142 -121
  489. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  490. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  491. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  492. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  493. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  494. package/src/assembly/webgpu-renderer.ts +666 -652
  495. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  496. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  497. package/src/components/camera.ts +287 -7
  498. package/src/components/index.ts +1 -0
  499. package/src/components/instances.ts +45 -18
  500. package/src/components/scene-instance.ts +2 -1
  501. package/src/components/screen-space-reflection.ts +21 -0
  502. package/src/components/sprite-animation.ts +2 -2
  503. package/src/components/sprite-instances.ts +1 -1
  504. package/src/device/gpu-residency.ts +34 -31
  505. package/src/environment/background.ts +263 -0
  506. package/src/errors/gpu-driven.ts +39 -5
  507. package/src/errors/render.ts +27 -3
  508. package/src/extract/camera.ts +26 -1
  509. package/src/extract/gpu-driven.ts +185 -10
  510. package/src/features/host.ts +237 -19
  511. package/src/features/noise-texture.ts +91 -0
  512. package/src/features/plan.ts +553 -24
  513. package/src/features/prepared-gpu-work.ts +631 -49
  514. package/src/features/prepared-graphics-store.ts +31 -0
  515. package/src/features/prepared-graphics.ts +5 -0
  516. package/src/features/render-graph-compute.ts +41 -8
  517. package/src/features/render-graph-contribution.ts +141 -3
  518. package/src/features/render-graph-raster.ts +143 -30
  519. package/src/features/types.ts +11 -0
  520. package/src/fullscreen-post-process-pass.ts +3 -0
  521. package/src/gpu-driven/batch-topology.ts +424 -102
  522. package/src/gpu-driven/pbr-program.ts +31 -0
  523. package/src/gpu-driven/prepared-draw.ts +29 -4
  524. package/src/gpu-driven/production-raster.ts +2267 -694
  525. package/src/gpu-driven/shadow-views.ts +539 -0
  526. package/src/gpu-driven/view-gpu.ts +188 -41
  527. package/src/gpu-scene-schema.ts +52 -11
  528. package/src/gpu-scene.ts +186 -99
  529. package/src/gpu-texture-usage.ts +1 -0
  530. package/src/hdrp-buffers.ts +72 -36
  531. package/src/ibl/frame-resources.ts +38 -0
  532. package/src/ibl/skylight-bind-group.ts +5 -4
  533. package/src/index.ts +109 -1
  534. package/src/inspection-types.ts +191 -0
  535. package/src/instances-derived-bounds.ts +258 -34
  536. package/src/instances.ts +459 -150
  537. package/src/internal.ts +22 -0
  538. package/src/lifecycle.ts +2 -0
  539. package/src/material-row.ts +145 -0
  540. package/src/materials.ts +44 -8
  541. package/src/pbr-pipeline.ts +159 -17
  542. package/src/pipeline/standard-forward-lane.ts +52 -24
  543. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  544. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  545. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  546. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  547. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  548. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  549. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  550. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  551. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  552. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  553. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  554. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  555. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  556. package/src/pipeline/standard-output/color-transform.ts +124 -0
  557. package/src/pipeline/standard-output/graph.ts +139 -0
  558. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  559. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  560. package/src/pipeline/standard-output/lut-state.ts +176 -0
  561. package/src/pipeline/standard-output/resources.ts +121 -0
  562. package/src/pipeline/standard-output/types.ts +58 -0
  563. package/src/pipeline/standard-pipeline.ts +192 -59
  564. package/src/pipeline/standard-post.ts +186 -27
  565. package/src/pipeline-builder.ts +16 -6
  566. package/src/pipeline-spec-types.ts +4 -0
  567. package/src/pipeline-spec.ts +37 -29
  568. package/src/points-lines/standard-owner.ts +6 -14
  569. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  570. package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
  571. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  572. package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
  573. package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
  574. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  575. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  576. package/src/record/dynamic-geometry-consumption.ts +59 -0
  577. package/src/record/frame-lighting.ts +12 -11
  578. package/src/record/frame-snapshot.ts +133 -23
  579. package/src/record/frame-targets.ts +9 -0
  580. package/src/record/frame.ts +725 -133
  581. package/src/record/main-pass-geometry.ts +149 -94
  582. package/src/record/main-pass-material.ts +115 -26
  583. package/src/record/main-pass-sprite-draws.ts +16 -107
  584. package/src/record/main-pass.ts +78 -8
  585. package/src/record/material-uniforms.ts +1 -1
  586. package/src/record/mesh-ssbo.ts +59 -15
  587. package/src/record/prepared-material-bindings.ts +234 -0
  588. package/src/record/recovery-pipeline.ts +59 -136
  589. package/src/record/render-context.ts +90 -22
  590. package/src/record/shadow-pass.ts +1231 -209
  591. package/src/record/skybox-post-pass.ts +14 -3
  592. package/src/record/typed-frame-graph.ts +1004 -44
  593. package/src/record/view-ubo.ts +11 -0
  594. package/src/recovery/render-system-candidate.ts +90 -66
  595. package/src/recovery/render-system-roots.ts +113 -0
  596. package/src/recovery/types.ts +77 -0
  597. package/src/reflection/record-owner.ts +26 -54
  598. package/src/render-contract.ts +195 -25
  599. package/src/render-graph-primitives.ts +6 -2
  600. package/src/render-pipeline.ts +70 -1
  601. package/src/render-system-extract-tail.ts +409 -160
  602. package/src/render-system-extract.ts +376 -102
  603. package/src/render-system-projections.ts +241 -0
  604. package/src/render-system.ts +681 -822
  605. package/src/scene/render-scene-types.ts +13 -4
  606. package/src/scene/render-scene.ts +569 -355
  607. package/src/scene/shadow-visibility.ts +21 -0
  608. package/src/ssr/admission.ts +380 -14
  609. package/src/ssr/compose.ts +144 -0
  610. package/src/ssr/errors.ts +48 -0
  611. package/src/ssr/graph.ts +777 -0
  612. package/src/ssr/history.ts +436 -0
  613. package/src/ssr/hiz.ts +124 -0
  614. package/src/ssr/inspection.ts +124 -0
  615. package/src/ssr/resources.ts +202 -0
  616. package/src/ssr/temporal.ts +164 -0
  617. package/src/systems/skin-palette-allocator.ts +495 -148
  618. package/src/systems/skin-palette-types.ts +17 -0
  619. package/src/systems/transparent-dispatch.ts +90 -0
  620. package/src/targets/material-source.ts +34 -0
  621. package/src/temporal/coverage.ts +1 -1
  622. package/src/temporal/frame-coordinator.ts +23 -2
  623. package/src/temporal/gpu.ts +74 -12
  624. package/src/temporal/history.ts +3 -1
  625. package/src/temporal/inspection.ts +2 -1
  626. package/src/temporal/standard-scene-data.ts +3 -1
  627. package/src/temporal/temporal-view.ts +3 -0
  628. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
  629. package/src/typed-render-graph-primitives.ts +266 -74
  630. package/src/typed-shadow-passes.ts +122 -12
  631. package/src/volume/temporal.ts +10 -0
  632. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  633. package/dist/chunk-GF523LHF.mjs.map +0 -1
  634. package/dist/chunk-IQMKJLNU.mjs.map +0 -1
  635. package/dist/chunk-J52NMQKR.mjs.map +0 -1
  636. package/dist/chunk-J6KACNOH.mjs.map +0 -1
  637. package/dist/chunk-JAASCMXA.mjs.map +0 -1
  638. package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
  639. package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
  640. package/dist/chunk-VSL23LZE.mjs.map +0 -1
  641. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  642. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -0,0 +1,291 @@
1
+ import { AUTO_EXPOSURE_PRESET_V1 } from './preset';
2
+
3
+ const RGB_TO_XYZ_D65 = [
4
+ [0.4124564, 0.3575761, 0.1804375],
5
+ [0.2126729, 0.7151522, 0.072175],
6
+ [0.0193339, 0.119192, 0.9503041],
7
+ ] as const;
8
+ const D65_XYZ = [0.95047, 1, 1.08883] as const;
9
+ const BRADFORD = [
10
+ [0.8951, 0.2664, -0.1614],
11
+ [-0.7502, 1.7135, 0.0367],
12
+ [0.0389, -0.0685, 1.0296],
13
+ ] as const;
14
+ const BRADFORD_INVERSE = [
15
+ [0.9869929, -0.1470543, 0.1599627],
16
+ [0.4323053, 0.5183603, 0.0492912],
17
+ [-0.0085287, 0.0400428, 0.9684867],
18
+ ] as const;
19
+
20
+ function multiply3(
21
+ matrix: readonly (readonly number[])[],
22
+ value: readonly [number, number, number],
23
+ ): [number, number, number] {
24
+ const row0 = matrix[0] ?? [0, 0, 0];
25
+ const row1 = matrix[1] ?? [0, 0, 0];
26
+ const row2 = matrix[2] ?? [0, 0, 0];
27
+ return [
28
+ (row0[0] ?? 0) * value[0] + (row0[1] ?? 0) * value[1] + (row0[2] ?? 0) * value[2],
29
+ (row1[0] ?? 0) * value[0] + (row1[1] ?? 0) * value[1] + (row1[2] ?? 0) * value[2],
30
+ (row2[0] ?? 0) * value[0] + (row2[1] ?? 0) * value[1] + (row2[2] ?? 0) * value[2],
31
+ ];
32
+ }
33
+
34
+ function blackbodyWhitePoint(temperature: number): [number, number, number] {
35
+ if (temperature === 6504) return [...D65_XYZ];
36
+ const t = Math.min(40000, Math.max(1000, temperature));
37
+ const x =
38
+ t <= 4000
39
+ ? -0.2661239e9 / t ** 3 - 0.234358e6 / t ** 2 + 0.8776956e3 / t + 0.17991
40
+ : -3.0258469e9 / t ** 3 + 2.1070379e6 / t ** 2 + 0.2226347e3 / t + 0.24039;
41
+ const y =
42
+ t <= 2222
43
+ ? -1.1063814 * x ** 3 - 1.3481102 * x ** 2 + 2.18555832 * x - 0.20219683
44
+ : t <= 4000
45
+ ? -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867
46
+ : 3.081758 * x ** 3 - 5.8733867 * x ** 2 + 3.75112997 * x - 0.37001483;
47
+ return [x / y, 1, (1 - x - y) / y];
48
+ }
49
+
50
+ export function luminanceHistogram(
51
+ pixels: readonly (readonly [number, number, number, number])[],
52
+ bins = AUTO_EXPOSURE_PRESET_V1.histogramBins,
53
+ ): Uint32Array {
54
+ const histogram = new Uint32Array(bins);
55
+ const min = AUTO_EXPOSURE_PRESET_V1.logLuminanceMin;
56
+ const max = AUTO_EXPOSURE_PRESET_V1.logLuminanceMax;
57
+ for (const pixel of pixels) {
58
+ const luminance = 0.2126 * pixel[0] + 0.7152 * pixel[1] + 0.0722 * pixel[2];
59
+ if (!Number.isFinite(luminance) || luminance <= 0) continue;
60
+ const normalized = (Math.log2(luminance) - min) / (max - min);
61
+ const index = Math.min(bins - 1, Math.max(0, Math.floor(normalized * bins)));
62
+ const bucket = histogram[index];
63
+ if (bucket !== undefined) histogram[index] = bucket + 1;
64
+ }
65
+ return histogram;
66
+ }
67
+
68
+ /**
69
+ * Mirror the fixed shader-side center weighting for deterministic tests. The
70
+ * sample list is row-major over the metering grid (one sample per 4x4 block),
71
+ * so the helper never changes the texture-read/sample-count contract.
72
+ */
73
+ export function centerWeight(
74
+ block: readonly [number, number],
75
+ sampleGrid: readonly [number, number],
76
+ ): number {
77
+ const centerX = (sampleGrid[0] - 1) * 0.5;
78
+ const centerY = (sampleGrid[1] - 1) * 0.5;
79
+ const extentX = Math.max(centerX, 1);
80
+ const extentY = Math.max(centerY, 1);
81
+ const offsetX = (block[0] - centerX) / extentX;
82
+ const offsetY = (block[1] - centerY) / extentY;
83
+ const radial = Math.max(0, 1 - offsetX * offsetX - offsetY * offsetY);
84
+ return 1 + Math.min(2, Math.floor(radial * 2 + 0.5));
85
+ }
86
+
87
+ export function weightedLuminanceHistogram(
88
+ pixels: readonly (readonly [number, number, number, number])[],
89
+ sampleGrid: readonly [number, number],
90
+ bins = AUTO_EXPOSURE_PRESET_V1.histogramBins,
91
+ ): Uint32Array {
92
+ const histogram = new Uint32Array(bins);
93
+ const min = AUTO_EXPOSURE_PRESET_V1.logLuminanceMin;
94
+ const max = AUTO_EXPOSURE_PRESET_V1.logLuminanceMax;
95
+ const width = Math.max(1, Math.floor(sampleGrid[0]));
96
+ const height = Math.max(1, Math.floor(sampleGrid[1]));
97
+ for (let index = 0; index < Math.min(pixels.length, width * height); index += 1) {
98
+ const pixel = pixels[index];
99
+ if (pixel === undefined) continue;
100
+ const luminance = 0.2126 * pixel[0] + 0.7152 * pixel[1] + 0.0722 * pixel[2];
101
+ if (!Number.isFinite(luminance) || luminance <= 0) continue;
102
+ const normalized = (Math.log2(luminance) - min) / (max - min);
103
+ const bucket = Math.min(bins - 1, Math.max(0, Math.floor(normalized * bins)));
104
+ const row = Math.floor(index / width);
105
+ const column = index - row * width;
106
+ const weight = centerWeight([column, row], [width, height]);
107
+ const current = histogram[bucket];
108
+ if (current !== undefined) histogram[bucket] = current + weight;
109
+ }
110
+ return histogram;
111
+ }
112
+
113
+ /** Fixed product target mapping used to compare GPU adaptation with a CPU oracle. */
114
+ export function autoExposureTarget(
115
+ histogram: Uint32Array,
116
+ compensationEv: number,
117
+ rangeEv: readonly [number, number],
118
+ fallback: number,
119
+ ): number {
120
+ if (
121
+ ![compensationEv, rangeEv[0], rangeEv[1], fallback].every(Number.isFinite) ||
122
+ fallback <= 0 ||
123
+ rangeEv[0] > rangeEv[1]
124
+ ) {
125
+ return fallback;
126
+ }
127
+ const total = histogram.reduce((sum, value) => sum + value, 0);
128
+ if (total <= 0) return fallback;
129
+ const lowRank = Math.min(total, Math.floor(total * 0.05));
130
+ const highRank = Math.min(total, Math.max(lowRank + 1, Math.ceil(total * 0.95)));
131
+ let cumulative = 0;
132
+ let clippedTotal = 0;
133
+ let clippedWeightedLog = 0;
134
+ for (let index = 0; index < histogram.length; index += 1) {
135
+ const count = histogram[index] ?? 0;
136
+ const begin = cumulative;
137
+ cumulative += count;
138
+ const keptBegin = Math.max(begin, lowRank);
139
+ const keptEnd = Math.min(cumulative, highRank);
140
+ if (keptEnd > keptBegin) {
141
+ const kept = keptEnd - keptBegin;
142
+ clippedTotal += kept;
143
+ clippedWeightedLog +=
144
+ kept *
145
+ (AUTO_EXPOSURE_PRESET_V1.logLuminanceMin +
146
+ (index + 0.5) *
147
+ ((AUTO_EXPOSURE_PRESET_V1.logLuminanceMax - AUTO_EXPOSURE_PRESET_V1.logLuminanceMin) /
148
+ histogram.length));
149
+ }
150
+ }
151
+ if (clippedTotal <= 0) return fallback;
152
+ const averageLog = clippedWeightedLog / clippedTotal;
153
+ const measuredExposure = 2 ** -averageLog * AUTO_EXPOSURE_PRESET_V1.middleGray;
154
+ if (!Number.isFinite(measuredExposure)) return fallback;
155
+ const targetEv = Math.min(
156
+ rangeEv[1],
157
+ Math.max(rangeEv[0], Math.log2(Math.max(measuredExposure, 1e-6)) + compensationEv),
158
+ );
159
+ const target = 2 ** targetEv;
160
+ return Number.isFinite(target) && target > 0 ? target : fallback;
161
+ }
162
+
163
+ export function histogramPercentile(histogram: Uint32Array, percentile: number): number {
164
+ const total = histogram.reduce((sum, value) => sum + value, 0);
165
+ if (total === 0) return 0;
166
+ const target = Math.min(total - 1, Math.max(0, Math.floor(percentile * total)));
167
+ let accumulated = 0;
168
+ for (let index = 0; index < histogram.length; index += 1) {
169
+ accumulated += histogram[index] ?? 0;
170
+ if (accumulated > target) {
171
+ return (
172
+ AUTO_EXPOSURE_PRESET_V1.logLuminanceMin +
173
+ ((index + 0.5) / histogram.length) *
174
+ (AUTO_EXPOSURE_PRESET_V1.logLuminanceMax - AUTO_EXPOSURE_PRESET_V1.logLuminanceMin)
175
+ );
176
+ }
177
+ }
178
+ return AUTO_EXPOSURE_PRESET_V1.logLuminanceMax;
179
+ }
180
+
181
+ export function adaptExposure(
182
+ current: number,
183
+ target: number,
184
+ deltaTime: number,
185
+ upRate: number,
186
+ downRate: number,
187
+ ): number {
188
+ if (![current, target, deltaTime, upRate, downRate].every(Number.isFinite)) return current;
189
+ if (deltaTime <= 0 || current === target) return current;
190
+ const rate = target > current ? Math.max(0, upRate) : Math.max(0, downRate);
191
+ if (rate === 0) return current;
192
+ const amount = 1 - Math.exp(-rate * deltaTime);
193
+ return current + (target - current) * amount;
194
+ }
195
+
196
+ export function bradfordAdaptD65(
197
+ rgb: readonly [number, number, number],
198
+ temperature: number,
199
+ ): [number, number, number] {
200
+ if (temperature === 6504) return [rgb[0], rgb[1], rgb[2]];
201
+ const source = multiply3(BRADFORD, D65_XYZ);
202
+ const target = multiply3(BRADFORD, blackbodyWhitePoint(temperature));
203
+ const scale: [number, number, number] = [
204
+ target[0] / source[0],
205
+ target[1] / source[1],
206
+ target[2] / source[2],
207
+ ];
208
+ const adaptedLms = multiply3(BRADFORD, multiply3(RGB_TO_XYZ_D65, rgb));
209
+ const adaptedXyz = multiply3(BRADFORD_INVERSE, [
210
+ adaptedLms[0] * scale[0],
211
+ adaptedLms[1] * scale[1],
212
+ adaptedLms[2] * scale[2],
213
+ ]);
214
+ return [adaptedXyz[0] / 0.95047, adaptedXyz[1], adaptedXyz[2] / 1.08883];
215
+ }
216
+
217
+ function labPivot(value: number): number {
218
+ const epsilon = (6 / 29) ** 3;
219
+ const kappa = (29 / 3) ** 3;
220
+ return value > epsilon ? Math.cbrt(value) : value * kappa + 4 / 29;
221
+ }
222
+
223
+ export function linearRgbToLab(rgb: readonly [number, number, number]): [number, number, number] {
224
+ const xyz = multiply3(RGB_TO_XYZ_D65, rgb);
225
+ const x = labPivot(xyz[0] / D65_XYZ[0]);
226
+ const y = labPivot(xyz[1] / D65_XYZ[1]);
227
+ const z = labPivot(xyz[2] / D65_XYZ[2]);
228
+ return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
229
+ }
230
+
231
+ export function ciede2000(
232
+ first: readonly [number, number, number],
233
+ second: readonly [number, number, number],
234
+ ): number {
235
+ const [l1, a1, b1] = first;
236
+ const [l2, a2, b2] = second;
237
+ const c1 = Math.hypot(a1, b1);
238
+ const c2 = Math.hypot(a2, b2);
239
+ const cBar = (c1 + c2) / 2;
240
+ const g = 0.5 * (1 - Math.sqrt(cBar ** 7 / (cBar ** 7 + 25 ** 7)));
241
+ const a1Prime = (1 + g) * a1;
242
+ const a2Prime = (1 + g) * a2;
243
+ const c1Prime = Math.hypot(a1Prime, b1);
244
+ const c2Prime = Math.hypot(a2Prime, b2);
245
+ const h1 = hueAngle(a1Prime, b1);
246
+ const h2 = hueAngle(a2Prime, b2);
247
+ const deltaL = l2 - l1;
248
+ const deltaC = c2Prime - c1Prime;
249
+ const deltaH = hueDelta(h1, h2, c1Prime * c2Prime);
250
+ const deltaBigH = 2 * Math.sqrt(c1Prime * c2Prime) * Math.sin(deltaH / 2);
251
+ const lBar = (l1 + l2) / 2;
252
+ const cBarPrime = (c1Prime + c2Prime) / 2;
253
+ const hBar = hueMean(h1, h2);
254
+ const t =
255
+ 1 -
256
+ 0.17 * Math.cos(hBar - Math.PI / 6) +
257
+ 0.24 * Math.cos(2 * hBar) +
258
+ 0.32 * Math.cos(3 * hBar + Math.PI / 30) -
259
+ 0.2 * Math.cos(4 * hBar - (21 * Math.PI) / 60);
260
+ const deltaTheta =
261
+ ((30 * Math.PI) / 180) * Math.exp(-((((hBar * 180) / Math.PI - 275) / 25) ** 2));
262
+ const rc = 2 * Math.sqrt(cBarPrime ** 7 / (cBarPrime ** 7 + 25 ** 7));
263
+ const sl = 1 + (0.015 * (lBar - 50) ** 2) / Math.sqrt(20 + (lBar - 50) ** 2);
264
+ const sc = 1 + 0.045 * cBarPrime;
265
+ const sh = 1 + 0.015 * cBarPrime * t;
266
+ const rt = -Math.sin(2 * deltaTheta) * rc;
267
+ return Math.sqrt(
268
+ (deltaL / sl) ** 2 +
269
+ (deltaC / sc) ** 2 +
270
+ (deltaBigH / sh) ** 2 +
271
+ rt * (deltaC / sc) * (deltaBigH / sh),
272
+ );
273
+ }
274
+
275
+ function hueAngle(a: number, b: number): number {
276
+ if (a === 0 && b === 0) return 0;
277
+ const angle = Math.atan2(b, a);
278
+ return angle >= 0 ? angle : angle + 2 * Math.PI;
279
+ }
280
+
281
+ function hueDelta(first: number, second: number, chromaProduct: number): number {
282
+ if (chromaProduct === 0) return 0;
283
+ const delta = second - first;
284
+ if (Math.abs(delta) <= Math.PI) return delta;
285
+ return delta > 0 ? delta - 2 * Math.PI : delta + 2 * Math.PI;
286
+ }
287
+
288
+ function hueMean(first: number, second: number): number {
289
+ if (Math.abs(first - second) <= Math.PI) return (first + second) / 2;
290
+ return (first + second + (first + second < 2 * Math.PI ? 2 * Math.PI : -2 * Math.PI)) / 2;
291
+ }
@@ -0,0 +1,28 @@
1
+ /** Versioned product constants. External standards supply formulas, not these values. */
2
+ export interface AutoExposurePreset {
3
+ readonly version: 'auto-exposure-v1';
4
+ readonly histogramBins: 256;
5
+ readonly sampleBlockSize: 4;
6
+ readonly lowPercentile: number;
7
+ readonly highPercentile: number;
8
+ readonly middleGray: number;
9
+ readonly logLuminanceMin: number;
10
+ readonly logLuminanceMax: number;
11
+ readonly referenceFormulas: readonly string[];
12
+ }
13
+
14
+ export const AUTO_EXPOSURE_PRESET_V1: AutoExposurePreset = Object.freeze({
15
+ version: 'auto-exposure-v1',
16
+ histogramBins: 256,
17
+ sampleBlockSize: 4,
18
+ lowPercentile: 0.05,
19
+ highPercentile: 0.95,
20
+ middleGray: 0.18,
21
+ logLuminanceMin: -12,
22
+ logLuminanceMax: 12,
23
+ referenceFormulas: Object.freeze([
24
+ 'linear-rgb-to-xyz-d65',
25
+ 'bradford-d65-adaptation',
26
+ 'cielab-delta-e-2000',
27
+ ]),
28
+ });
@@ -0,0 +1,156 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import {
3
+ AutoExposureInvalidParameterError,
4
+ type AutoExposureReceipt,
5
+ type AutoExposureResetReason,
6
+ AutoExposureStaleGenerationError,
7
+ } from './inspection';
8
+
9
+ /** CPU-side ownership record for the two GPU state slots and accepted candidate. */
10
+ export interface AutoExposureState {
11
+ readonly acceptedEv: number;
12
+ readonly fallback: number;
13
+ readonly lastKnownGood: number;
14
+ readonly targetGeneration: number;
15
+ readonly deviceEpoch: number;
16
+ readonly reset: readonly AutoExposureResetReason[];
17
+ readonly receipt: AutoExposureReceipt;
18
+ }
19
+
20
+ export interface AutoExposureCandidate {
21
+ readonly ev: number;
22
+ readonly generation: number;
23
+ readonly deviceEpoch: number;
24
+ readonly frameId: number;
25
+ }
26
+
27
+ export interface AutoExposureSubmissionMetadata {
28
+ readonly generation: number;
29
+ readonly deviceEpoch: number;
30
+ readonly frameId: number;
31
+ }
32
+
33
+ function finite(value: number): boolean {
34
+ return Number.isFinite(value);
35
+ }
36
+
37
+ export function createAutoExposureState(input: {
38
+ readonly fallback: number;
39
+ readonly targetGeneration?: number;
40
+ readonly deviceEpoch?: number;
41
+ readonly frameId?: number;
42
+ }): Result<AutoExposureState, AutoExposureInvalidParameterError> {
43
+ if (!finite(input.fallback) || input.fallback <= 0) {
44
+ return err(
45
+ new AutoExposureInvalidParameterError({
46
+ field: 'fallback',
47
+ value: input.fallback,
48
+ expected: 'a finite positive multiplier',
49
+ }),
50
+ );
51
+ }
52
+ const targetGeneration = input.targetGeneration ?? 0;
53
+ const deviceEpoch = input.deviceEpoch ?? 0;
54
+ const frameId = input.frameId ?? 0;
55
+ if (!Number.isInteger(targetGeneration) || targetGeneration < 0) {
56
+ return err(
57
+ new AutoExposureInvalidParameterError({
58
+ field: 'targetGeneration',
59
+ value: targetGeneration,
60
+ expected: 'a non-negative integer',
61
+ }),
62
+ );
63
+ }
64
+ return ok(
65
+ Object.freeze({
66
+ acceptedEv: 0,
67
+ fallback: input.fallback,
68
+ lastKnownGood: input.fallback,
69
+ targetGeneration,
70
+ deviceEpoch,
71
+ reset: Object.freeze([]),
72
+ receipt: Object.freeze({ frameId, committed: false }),
73
+ }),
74
+ );
75
+ }
76
+
77
+ export function prepareAutoExposureCandidate(
78
+ state: AutoExposureState,
79
+ candidate: AutoExposureCandidate,
80
+ ): Result<
81
+ AutoExposureCandidate,
82
+ AutoExposureStaleGenerationError | AutoExposureInvalidParameterError
83
+ > {
84
+ if (!finite(candidate.ev) || candidate.ev <= 0) {
85
+ return err(
86
+ new AutoExposureInvalidParameterError({
87
+ field: 'candidate.ev',
88
+ value: candidate.ev,
89
+ expected: 'a finite positive multiplier',
90
+ }),
91
+ );
92
+ }
93
+ if (
94
+ candidate.generation !== state.targetGeneration ||
95
+ candidate.deviceEpoch !== state.deviceEpoch
96
+ ) {
97
+ return err(
98
+ new AutoExposureStaleGenerationError({
99
+ expectedGeneration: state.targetGeneration,
100
+ actualGeneration: candidate.generation,
101
+ }),
102
+ );
103
+ }
104
+ return ok(Object.freeze({ ...candidate }));
105
+ }
106
+
107
+ /** Publish a candidate only after the owning frame transaction has submitted. */
108
+ export function commitAutoExposureCandidate(
109
+ state: AutoExposureState,
110
+ candidate: AutoExposureCandidate,
111
+ ): AutoExposureState {
112
+ return Object.freeze({
113
+ ...state,
114
+ acceptedEv: candidate.ev,
115
+ lastKnownGood: candidate.ev,
116
+ receipt: Object.freeze({ frameId: candidate.frameId, committed: true }),
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Publish only the successful-submit receipt for the live GPU path.
122
+ *
123
+ * The numeric candidate is produced and retained by the GPU state buffer. No
124
+ * CPU readback is permitted on the frame path, so this transaction helper must
125
+ * not manufacture an accepted exposure from fallback/LKG data.
126
+ */
127
+ export function commitAutoExposureSubmission(
128
+ state: AutoExposureState,
129
+ metadata: AutoExposureSubmissionMetadata,
130
+ ): AutoExposureState {
131
+ if (
132
+ metadata.generation !== state.targetGeneration ||
133
+ metadata.deviceEpoch !== state.deviceEpoch
134
+ ) {
135
+ return state;
136
+ }
137
+ return Object.freeze({
138
+ ...state,
139
+ receipt: Object.freeze({ frameId: metadata.frameId, committed: true }),
140
+ });
141
+ }
142
+
143
+ /** Reset GPU state ownership while retaining the accepted EV as the fallback. */
144
+ export function resetAutoExposureState(
145
+ state: AutoExposureState,
146
+ reason: AutoExposureResetReason,
147
+ input: { readonly targetGeneration: number; readonly deviceEpoch: number },
148
+ ): AutoExposureState {
149
+ return Object.freeze({
150
+ ...state,
151
+ targetGeneration: input.targetGeneration,
152
+ deviceEpoch: input.deviceEpoch,
153
+ reset: Object.freeze([...state.reset, reason]),
154
+ receipt: Object.freeze({ ...state.receipt, committed: false }),
155
+ });
156
+ }
@@ -0,0 +1,124 @@
1
+ import type { ColorValueDomain } from '@forgeax/engine-render-graph';
2
+ import { bradfordAdaptD65 } from './auto-exposure/oracle';
3
+ import type { StandardOutputEncoding, StandardOutputLogicalStage } from './types';
4
+
5
+ export interface StandardOutputDomainTransition {
6
+ readonly stage: StandardOutputLogicalStage;
7
+ readonly input: ColorValueDomain;
8
+ readonly output: ColorValueDomain;
9
+ }
10
+
11
+ export const LINEAR_HDR_DOMAIN: ColorValueDomain = 'linear-hdr';
12
+ export const LINEAR_LDR_DOMAIN: ColorValueDomain = 'linear-ldr';
13
+ export const DISPLAY_ENCODED_DOMAIN: ColorValueDomain = 'display-encoded';
14
+
15
+ /** D65 product white point shared by the Camera output oracle. */
16
+ export const D65_TEMPERATURE_KELVIN = 6504;
17
+ export const CAMERA_COLOR_LUT_ZERO_COST_STRENGTH = 0;
18
+
19
+ export function outputEncodingOwner(encoding: StandardOutputEncoding): string {
20
+ return encoding === 'explicit-oetf' ? 'output-encoding.wgsl' : 'srgb-attachment';
21
+ }
22
+
23
+ export function outputEncodingUsesOetf(encoding: StandardOutputEncoding): boolean {
24
+ return encoding === 'explicit-oetf';
25
+ }
26
+
27
+ export type StandardRgb = readonly [number, number, number];
28
+ export type StandardRgba = readonly [number, number, number, number];
29
+
30
+ /** Apply the camera's Bradford white-balance adaptation in linear HDR. */
31
+ export function applyStandardWhiteBalance(
32
+ rgb: StandardRgb,
33
+ temperature: number,
34
+ tint: number,
35
+ ): [number, number, number] {
36
+ const adapted = bradfordAdaptD65(rgb, temperature);
37
+ if (tint === 0) return adapted;
38
+ const greenScale = Math.max(0, 1 - tint);
39
+ const magentaScale = Math.max(0, 1 + tint);
40
+ return [adapted[0] * magentaScale, adapted[1] * greenScale, adapted[2] * magentaScale];
41
+ }
42
+
43
+ export interface StandardColorLutData {
44
+ readonly size: number;
45
+ /** RGBA half-float texels in z-major, y-major, x-major order. */
46
+ readonly data: ArrayLike<number>;
47
+ }
48
+
49
+ function halfToFloat(value: number): number {
50
+ const sign = (value & 0x8000) === 0 ? 1 : -1;
51
+ const exponent = (value >>> 10) & 0x1f;
52
+ const mantissa = value & 0x3ff;
53
+ if (exponent === 0) return sign * 2 ** -14 * (mantissa / 1024);
54
+ if (exponent === 0x1f) return mantissa === 0 ? sign * Infinity : Number.NaN;
55
+ return sign * 2 ** (exponent - 15) * (1 + mantissa / 1024);
56
+ }
57
+
58
+ function lutValue(data: ArrayLike<number>, index: number): number {
59
+ const value = data[index] ?? 0;
60
+ if (data instanceof Uint8Array) {
61
+ const byte = index * 2;
62
+ return halfToFloat((data[byte] ?? 0) | ((data[byte + 1] ?? 0) << 8));
63
+ }
64
+ return data instanceof Uint16Array ? halfToFloat(value) : value;
65
+ }
66
+
67
+ function sampleNearest(data: StandardColorLutData, x: number, y: number, z: number): StandardRgba {
68
+ const size = data.size;
69
+ const texel = ((z * size + y) * size + x) * 4;
70
+ return [
71
+ lutValue(data.data, texel),
72
+ lutValue(data.data, texel + 1),
73
+ lutValue(data.data, texel + 2),
74
+ lutValue(data.data, texel + 3),
75
+ ];
76
+ }
77
+
78
+ /** CPU reference for the fixed clamp-to-edge, texel-center trilinear LUT sample. */
79
+ export function sampleStandardColorLut(
80
+ data: StandardColorLutData,
81
+ rgb: StandardRgb,
82
+ strength = 1,
83
+ alpha = 1,
84
+ ): StandardRgba {
85
+ if (!Number.isInteger(data.size) || data.size < 2) return [rgb[0], rgb[1], rgb[2], alpha];
86
+ const size = data.size;
87
+ const coordinate = rgb.map((value) =>
88
+ Math.min(size - 1, Math.max(0, Math.min(1, value) * size - 0.5)),
89
+ ) as [number, number, number];
90
+ const base = coordinate.map(Math.floor) as [number, number, number];
91
+ const fraction: [number, number, number] = [
92
+ coordinate[0] - base[0],
93
+ coordinate[1] - base[1],
94
+ coordinate[2] - base[2],
95
+ ];
96
+ const sampled: [number, number, number, number] = [0, 0, 0, 0];
97
+ for (let dz = 0; dz <= 1; dz += 1) {
98
+ for (let dy = 0; dy <= 1; dy += 1) {
99
+ for (let dx = 0; dx <= 1; dx += 1) {
100
+ const sample = sampleNearest(
101
+ data,
102
+ Math.min(size - 1, base[0] + dx),
103
+ Math.min(size - 1, base[1] + dy),
104
+ Math.min(size - 1, base[2] + dz),
105
+ );
106
+ const weight =
107
+ (dx === 0 ? 1 - fraction[0] : fraction[0]) *
108
+ (dy === 0 ? 1 - fraction[1] : fraction[1]) *
109
+ (dz === 0 ? 1 - fraction[2] : fraction[2]);
110
+ sampled[0] += sample[0] * weight;
111
+ sampled[1] += sample[1] * weight;
112
+ sampled[2] += sample[2] * weight;
113
+ sampled[3] += sample[3] * weight;
114
+ }
115
+ }
116
+ }
117
+ const amount = Math.min(1, Math.max(0, strength));
118
+ return [
119
+ rgb[0] + (sampled[0] - rgb[0]) * amount,
120
+ rgb[1] + (sampled[1] - rgb[1]) * amount,
121
+ rgb[2] + (sampled[2] - rgb[2]) * amount,
122
+ alpha,
123
+ ];
124
+ }