@photivra/engine 2.13.0 → 2.14.1

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 (128) hide show
  1. package/CHANGELOG.md +75 -1
  2. package/CITATION.cff +1 -1
  3. package/NOTICE +5 -4
  4. package/README.md +10 -8
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +16 -10
  7. package/dist/camera/lens-projection.js +2 -1
  8. package/dist/camera/lens-projection.js.map +1 -1
  9. package/dist/capture/dng-import.js +1 -1
  10. package/dist/capture/dng-import.js.map +1 -1
  11. package/dist/capture/host-yield-cadence.js +1 -1
  12. package/dist/capture/host-yield-cadence.js.map +1 -1
  13. package/dist/capture/native-environment-optical-stage.js +1 -1
  14. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  15. package/dist/capture/native-raw.js +1 -1
  16. package/dist/capture/native-raw.js.map +1 -1
  17. package/dist/capture/packed-sensor-raw.js +3 -3
  18. package/dist/capture/packed-sensor-raw.js.map +1 -1
  19. package/dist/capture/sensor-raw-producer.js +1 -1
  20. package/dist/capture/sensor-raw-producer.js.map +1 -1
  21. package/dist/color/capture-color.js +3 -3
  22. package/dist/color/capture-color.js.map +1 -1
  23. package/dist/color/chromatic-adaptation.js +2 -2
  24. package/dist/color/chromatic-adaptation.js.map +1 -1
  25. package/dist/color/color-matching-functions.js +1 -1
  26. package/dist/color/color-matching-functions.js.map +1 -1
  27. package/dist/color/colorimetry-math.js +2 -2
  28. package/dist/color/colorimetry-math.js.map +1 -1
  29. package/dist/color/illuminants.js +3 -3
  30. package/dist/color/illuminants.js.map +1 -1
  31. package/dist/color/rgb-color-spaces.js +1 -1
  32. package/dist/color/rgb-color-spaces.js.map +1 -1
  33. package/dist/color/sensor-color-development.js +1 -1
  34. package/dist/color/sensor-color-development.js.map +1 -1
  35. package/dist/core/record-validation.js +3 -3
  36. package/dist/core/record-validation.js.map +1 -1
  37. package/dist/core/version.d.ts +1 -1
  38. package/dist/core/version.js +1 -1
  39. package/dist/core/version.js.map +1 -1
  40. package/dist/equipment/generic-prime-lenses.js +3 -3
  41. package/dist/equipment/generic-prime-lenses.js.map +1 -1
  42. package/dist/equipment/generic-tier-assets.d.ts +23 -1
  43. package/dist/equipment/generic-tier-assets.js +58 -30
  44. package/dist/equipment/generic-tier-assets.js.map +1 -1
  45. package/dist/equipment/generic-tier-presets.d.ts +6 -3
  46. package/dist/equipment/generic-tier-presets.js +26 -13
  47. package/dist/equipment/generic-tier-presets.js.map +1 -1
  48. package/dist/exposure/auto-iso-slowest-shutter.js +2 -1
  49. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  50. package/dist/exposure/flash-ttl.js +1 -1
  51. package/dist/exposure/flash-ttl.js.map +1 -1
  52. package/dist/exposure/flash.js +1 -1
  53. package/dist/exposure/flash.js.map +1 -1
  54. package/dist/facade/chart-material-layers.js +2 -2
  55. package/dist/facade/chart-material-layers.js.map +1 -1
  56. package/dist/facade/chart-radiance-batch.js +1 -1
  57. package/dist/facade/chart-radiance-batch.js.map +1 -1
  58. package/dist/facade/chart-scenes.d.ts +45 -8
  59. package/dist/facade/chart-scenes.js +101 -44
  60. package/dist/facade/chart-scenes.js.map +1 -1
  61. package/dist/facade/color-patches.d.ts +129 -0
  62. package/dist/facade/color-patches.js +209 -0
  63. package/dist/facade/color-patches.js.map +1 -0
  64. package/dist/facade/display-view-gpu.js +1 -1
  65. package/dist/facade/display-view-gpu.js.map +1 -1
  66. package/dist/facade/scene-radiance.js +2 -2
  67. package/dist/facade/scene-radiance.js.map +1 -1
  68. package/dist/facade/simulate-capture.d.ts +47 -3
  69. package/dist/facade/simulate-capture.js +71 -22
  70. package/dist/facade/simulate-capture.js.map +1 -1
  71. package/dist/facade/simulate-display-view.js +2 -2
  72. package/dist/facade/simulate-display-view.js.map +1 -1
  73. package/dist/gpu/chart-composite-gpu.js +2 -2
  74. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  75. package/dist/gpu/display-view-composite-material-module.js +1 -1
  76. package/dist/gpu/display-view-composite-material-module.js.map +1 -1
  77. package/dist/gpu/image-kernel-execution.js +2 -2
  78. package/dist/gpu/image-kernel-execution.js.map +1 -1
  79. package/dist/gpu/temporal-sum-gpu.js +23 -23
  80. package/dist/gpu/webgpu-runtime.js +1 -1
  81. package/dist/gpu/webgpu-runtime.js.map +1 -1
  82. package/dist/gpu/wgsl-chart-composite-kernel.js +318 -318
  83. package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -1
  84. package/dist/gpu/wgsl-chart-kernel.js +117 -117
  85. package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
  86. package/dist/gpu/wgsl-display-view-quality-kernel.js +505 -505
  87. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  88. package/dist/gpu/wgsl-display-view-speed-kernel.js +248 -248
  89. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  90. package/dist/gpu/wgsl-kernels.js +203 -203
  91. package/dist/gpu/wgsl-kernels.js.map +1 -1
  92. package/dist/gpu/wgsl-sensor-kernel.js +302 -302
  93. package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
  94. package/dist/index.d.ts +5 -3
  95. package/dist/index.js +4 -2
  96. package/dist/index.js.map +1 -1
  97. package/dist/motion/temporal-exposure-sum.js +1 -1
  98. package/dist/motion/temporal-exposure-sum.js.map +1 -1
  99. package/dist/optics/diffraction-psf-profile.js +4 -4
  100. package/dist/optics/diffraction-psf-profile.js.map +1 -1
  101. package/dist/optics/front-of-lens-filter.js +1 -1
  102. package/dist/optics/front-of-lens-filter.js.map +1 -1
  103. package/dist/optics/irradiance-convolution.js +1 -1
  104. package/dist/optics/irradiance-convolution.js.map +1 -1
  105. package/dist/output/native-capture-sdr.js +1 -1
  106. package/dist/output/native-capture-sdr.js.map +1 -1
  107. package/dist/output/png-encoder.js +2 -2
  108. package/dist/output/png-encoder.js.map +1 -1
  109. package/dist/output/print-contrast-reference.js +2 -2
  110. package/dist/output/print-contrast-reference.js.map +1 -1
  111. package/dist/output/print-jpeg.js +1 -1
  112. package/dist/output/print-jpeg.js.map +1 -1
  113. package/dist/sensor/fixed-pattern-noise.js +1 -1
  114. package/dist/sensor/fixed-pattern-noise.js.map +1 -1
  115. package/dist/sensor/readout-exposure-linkage.js +1 -1
  116. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  117. package/docs/API_REFERENCE.md +29 -1
  118. package/docs/QUICK_START.md +40 -5
  119. package/docs/USAGE.md +35 -1
  120. package/docs/api/core-version.md +1 -1
  121. package/docs/api/equipment-generic-tier-assets.md +41 -1
  122. package/docs/api/equipment-generic-tier-presets.md +11 -3
  123. package/docs/api/exports.json +107 -2
  124. package/docs/api/facade-chart-scenes.md +36 -5
  125. package/docs/api/facade-color-patches.md +150 -0
  126. package/docs/api/facade-simulate-capture.md +52 -2
  127. package/llms.txt +1 -0
  128. package/package.json +2 -2
@@ -64,12 +64,12 @@
64
64
  import { DIGIT_SEGMENTS, NUMERAL_ADVANCE, SEGMENTS } from "../facade/chart-scenes.js";
65
65
  export const CHART_COMPOSITE_WORKGROUP_SIZE = 256;
66
66
  /** Element kind codes of the record headers. */
67
- export const CHART_ELEMENT_KIND = Object.freeze({ uniform: 0, "slanted-edge": 1, "siemens-star": 2, "step-wedge": 3, checkerboard: 5, "point-grid": 6, patches: 7,
67
+ export const CHART_ELEMENT_KIND = /* @__PURE__ */ Object.freeze({ uniform: 0, "slanted-edge": 1, "siemens-star": 2, "step-wedge": 3, checkerboard: 5, "point-grid": 6, patches: 7,
68
68
  "dead-leaves": 8, "bar-groups": 9, "hyperbolic-wedge": 10, "zone-plate": 11, "slanted-squares": 12, "line-grid": 13, fiducial: 14 });
69
69
  /** Placement modes of an element record: the background fills the frame; elements are rectangles or ellipses. */
70
- export const CHART_PLACEMENT = Object.freeze({ frame: 0, rectangle: 1, ellipse: 2 });
70
+ export const CHART_PLACEMENT = /* @__PURE__ */ Object.freeze({ frame: 0, rectangle: 1, ellipse: 2 });
71
71
  /** Words per element header, layer header and shape header in the u32 record array. */
72
- export const CHART_RECORD_STRIDE = Object.freeze({ element: 8, layer: 16, shape: 4, placementFloats: 10, barGroupFloats: 16 });
72
+ export const CHART_RECORD_STRIDE = /* @__PURE__ */ Object.freeze({ element: 8, layer: 16, shape: 4, placementFloats: 10, barGroupFloats: 16 });
73
73
  const SEGMENT_ORDER = "abcdefg";
74
74
  const segmentRows = SEGMENT_ORDER.split("").map((s) => `vec4<f32>(${SEGMENTS[s].map((x) => x.toFixed(2)).join(", ")})`).join(", ");
75
75
  const digitMasks = DIGIT_SEGMENTS.map((segments) => segments.split("").reduce((mask, s) => mask | (1 << SEGMENT_ORDER.indexOf(s)), 0)).map((m) => m + "u").join(", ");
@@ -88,50 +88,50 @@ struct B { v: f32, e: f32 }
88
88
 
89
89
  var<private> flagged: bool;
90
90
 
91
- // --- double-float32 (evaluation order matters; the host probes it) ---
92
- // The rounding barrier (2.11.0): ob(x) is x, its bits XORed with a word the host sets to 0 (a uniform), so a
93
- // compiler cannot know it is x. Every operation of the error-free transforms is wrapped, so none can be fused with or
94
- // reassociated across its neighbours (W3C WGSL § 15.7.5 permits both; Metal's compiler simplifies (a + b) - a to b, the M5 Pro
95
- // probe of October 27, 2026), and each rounds once, as written. On a device that already evaluates as written it changes nothing.
91
+
92
+
93
+
94
+
95
+
96
96
  fn ob(x: f32) -> f32 { return bitcast<f32>(bitcast<u32>(x) ^ BARRIER_ZERO); }
97
97
  fn two_sum(a: f32, b: f32) -> D { let s = ob(a + b); let bb = ob(s - a); let e = ob(ob(a - ob(s - bb)) + ob(b - bb)); return D(s, e); }
98
98
  fn quick_two_sum(a: f32, b: f32) -> D { let s = ob(a + b); let e = ob(b - ob(s - a)); return D(s, e); }
99
- // The Dekker product path: Veltkamp's split and Dekker's TwoProduct, exact only when every + - x is evaluated unfused as written.
99
+
100
100
  fn split(a: f32) -> D { let t = ob(4097.0 * a); let h = ob(t - ob(t - a)); return D(h, ob(a - h)); }
101
101
  fn two_prod_dekker(a: f32, b: f32) -> D {
102
- let p = ob(a * b); let sa = split(a); let sb = split(b);
103
- let e = ob(ob(ob(ob(ob(sa.h * sb.h) - p) + ob(sa.h * sb.l)) + ob(sa.l * sb.h)) + ob(sa.l * sb.l));
104
- return D(p, e);
102
+ let p = ob(a * b); let sa = split(a); let sb = split(b);
103
+ let e = ob(ob(ob(ob(ob(sa.h * sb.h) - p) + ob(sa.h * sb.l)) + ob(sa.l * sb.h)) + ob(sa.l * sb.l));
104
+ return D(p, e);
105
105
  }
106
106
  fn d_mul_dekker(a: D, b: D) -> D {
107
- let p = two_prod_dekker(a.h, b.h);
108
- let t = ob(ob(a.h * b.l) + ob(a.l * b.h));
109
- let l = ob(p.l + t);
110
- return quick_two_sum(p.h, l);
111
- }
112
- // The fma product path, for a device whose fma is fused (the probe checks it): TwoProduct as fma(a, b, -p), and a double-word
113
- // product in which no rounded product is an operand of an addition (the hi part is fma(a.h, b.h, t), its error fma(a.h, b.h, -s)),
114
- // so a contraction of a*b + c into one rounding cannot change it; only t, an ordinary bounded sum, may be contracted.
107
+ let p = two_prod_dekker(a.h, b.h);
108
+ let t = ob(ob(a.h * b.l) + ob(a.l * b.h));
109
+ let l = ob(p.l + t);
110
+ return quick_two_sum(p.h, l);
111
+ }
112
+
113
+
114
+
115
115
  fn two_prod_fma(a: f32, b: f32) -> D { let p = ob(a * b); return D(p, ob(fma(a, b, -p))); }
116
116
  fn d_mul_fma(a: D, b: D) -> D {
117
- let t = ob(ob(a.h * b.l) + ob(a.l * b.h));
118
- let s = ob(fma(a.h, b.h, t));
119
- return D(s, ob(ob(fma(a.h, b.h, -s)) + t));
117
+ let t = ob(ob(a.h * b.l) + ob(a.l * b.h));
118
+ let s = ob(fma(a.h, b.h, t));
119
+ return D(s, ob(ob(fma(a.h, b.h, -s)) + t));
120
120
  }
121
121
  fn d_add(a: D, b: D) -> D {
122
- let s = two_sum(a.h, b.h); let t = two_sum(a.l, b.l);
123
- let c = ob(s.l + t.h); let v = quick_two_sum(s.h, c);
124
- let w = ob(v.l + t.l); return quick_two_sum(v.h, w);
122
+ let s = two_sum(a.h, b.h); let t = two_sum(a.l, b.l);
123
+ let c = ob(s.l + t.h); let v = quick_two_sum(s.h, c);
124
+ let w = ob(v.l + t.l); return quick_two_sum(v.h, w);
125
125
  }
126
126
  fn d_neg(a: D) -> D { return D(-a.h, -a.l); }
127
127
  fn d_sub(a: D, b: D) -> D { return d_add(a, d_neg(b)); }
128
128
  fn d_mul(a: D, b: D) -> D { return d_mul_PRODUCT_PATH(a, b); }
129
- // A double-float32 result as a bounded value: its high part, with the low part and the declared 2^-40 error, relative to the
130
- // result and to \`scale\`, the magnitude of the operands it was formed from (a difference of nearly equal terms keeps their error).
129
+
130
+
131
131
  fn bds(a: D, scale: f32) -> B { return B(a.h, abs(a.l) + DW * (abs(a.h) + abs(a.l) + scale) + TINY); }
132
132
  fn bd(a: D) -> B { return bds(a, 0.0); }
133
133
 
134
- // --- bound arithmetic (each value rounds once, as written: the barrier keeps a compiler from regrouping them) ---
134
+
135
135
  fn bc(c: f32) -> B { return B(c, E * abs(c) + TINY); }
136
136
  fn bx(c: f32) -> B { return B(c, 0.0); }
137
137
  fn badd(a: B, b: B) -> B { let v = ob(a.v + b.v); return B(v, a.e + b.e + E * abs(v)); }
@@ -139,27 +139,27 @@ fn bsub(a: B, b: B) -> B { let v = ob(a.v - b.v); return B(v, a.e + b.e + E * ab
139
139
  fn bmul(a: B, b: B) -> B { let v = ob(a.v * b.v); return B(v, abs(a.v) * b.e + abs(b.v) * a.e + a.e * b.e + E * abs(v)); }
140
140
  fn bneg(a: B) -> B { return B(-a.v, a.e); }
141
141
  fn babs(a: B) -> B { return B(abs(a.v), a.e); }
142
- // WGSL division: 2.5 ULP (at most 5u relative) for a denominator within the normal range; a denominator within its bound of 0 flags.
142
+
143
143
  fn bdiv(a: B, b: B) -> B {
144
- let v = ob(a.v / b.v);
145
- let d = abs(b.v) - SAFETY * b.e;
146
- if (!(d > 0.0)) { flagged = true; return B(v, 3.0e38); }
147
- let e = (a.e + (abs(a.v) + a.e) * b.e / d) / abs(b.v) + 5.0 * E * abs(v);
148
- return B(v, e);
144
+ let v = ob(a.v / b.v);
145
+ let d = abs(b.v) - SAFETY * b.e;
146
+ if (!(d > 0.0)) { flagged = true; return B(v, 3.0e38); }
147
+ let e = (a.e + (abs(a.v) + a.e) * b.e / d) / abs(b.v) + 5.0 * E * abs(v);
148
+ return B(v, e);
149
149
  }
150
150
  fn margin(x: B) -> f32 { return SAFETY * x.e + SLACK * (abs(x.v) + 1.0); }
151
- // x >= 0 for the exact value; flags when the sign is not decided by the bound.
151
+
152
152
  fn ge0(x: B) -> bool { if (!(abs(x.v) > margin(x))) { flagged = true; } return x.v >= 0.0; }
153
153
  fn ge(a: B, b: B) -> bool { return ge0(bsub(a, b)); }
154
154
  fn gt(a: B, b: B) -> bool { return !ge0(bsub(b, a)); }
155
155
  fn lt(a: B, b: B) -> bool { return !ge0(bsub(a, b)); }
156
156
  fn le(a: B, b: B) -> bool { return ge0(bsub(b, a)); }
157
- // floor of the exact value; flags when x lies within its margin of an integer in [lo, hi] (or when the margin is a half or more).
157
+
158
158
  fn bfloor(x: B, lo: f32, hi: f32) -> f32 {
159
- let n = floor(x.v); let m = round(x.v); let g = margin(x);
160
- if (g >= 0.5) { flagged = true; return n; }
161
- if (m >= lo && m <= hi && !(abs(x.v - m) > g)) { flagged = true; }
162
- return n;
159
+ let n = floor(x.v); let m = round(x.v); let g = margin(x);
160
+ if (g >= 0.5) { flagged = true; return n; }
161
+ if (m >= lo && m <= hi && !(abs(x.v - m) > g)) { flagged = true; }
162
+ return n;
163
163
  }
164
164
  fn parity_even(i: i32, j: i32) -> bool { return ((i + j) & 1) == 0; }
165
165
  `;
@@ -168,7 +168,7 @@ const commonWgsl = (path, zero) => COMMON_TEMPLATE.replace("d_mul_PRODUCT_PATH",
168
168
  /** The composite kernel compiled with one product path (`d_mul`): the probe's choice for the device. */
169
169
  export function chartCompositeWgsl(path) {
170
170
  return /* wgsl */ `${commonWgsl(path, "params.zero")}
171
- // zero: 0, set by the host; the rounding barrier's word.
171
+
172
172
  struct Params { count: u32, columns: u32, wavelength_mode: u32, zero: u32 };
173
173
  @group(0) @binding(0) var<uniform> params: Params;
174
174
  @group(0) @binding(1) var<storage, read> points: array<vec4<f32>>;
@@ -183,297 +183,297 @@ const SEGMENT_BOX = array<vec4<f32>, 7>(${segmentRows});
183
183
  const DIGIT_MASK = array<u32, 10>(${digitMasks});
184
184
  const NUMERAL_ADVANCE: f32 = ${NUMERAL_ADVANCE};
185
185
 
186
- // --- Taylor cos and sin on [0, pi/4 + eps] in bound arithmetic (remainders 4e-13 and 2e-14) ---
186
+
187
187
  fn bcos_poly(y: B) -> B {
188
- let t = bmul(y, y);
189
- var p = bc(2.08767569878681e-9);
190
- p = badd(bmul(p, t), bc(-2.755731922398589e-7));
191
- p = badd(bmul(p, t), bc(2.48015873015873e-5));
192
- p = badd(bmul(p, t), bc(-0.001388888888888889));
193
- p = badd(bmul(p, t), bc(0.041666666666666664));
194
- p = badd(bmul(p, t), bc(-0.5));
195
- p = badd(bmul(p, t), bc(1.0));
196
- return B(p.v, p.e + 4.0e-13);
188
+ let t = bmul(y, y);
189
+ var p = bc(2.08767569878681e-9);
190
+ p = badd(bmul(p, t), bc(-2.755731922398589e-7));
191
+ p = badd(bmul(p, t), bc(2.48015873015873e-5));
192
+ p = badd(bmul(p, t), bc(-0.001388888888888889));
193
+ p = badd(bmul(p, t), bc(0.041666666666666664));
194
+ p = badd(bmul(p, t), bc(-0.5));
195
+ p = badd(bmul(p, t), bc(1.0));
196
+ return B(p.v, p.e + 4.0e-13);
197
197
  }
198
198
  fn bsin_poly(z: B) -> B {
199
- let t = bmul(z, z);
200
- var p = bc(1.605904383682161e-10);
201
- p = badd(bmul(p, t), bc(-2.505210838544172e-8));
202
- p = badd(bmul(p, t), bc(2.7557319223985893e-6));
203
- p = badd(bmul(p, t), bc(-0.0001984126984126984));
204
- p = badd(bmul(p, t), bc(0.008333333333333333));
205
- p = badd(bmul(p, t), bc(-0.16666666666666666));
206
- p = badd(bmul(p, t), bc(1.0));
207
- let s = bmul(p, z);
208
- return B(s.v, s.e + 2.0e-14);
209
- }
210
- // cos(x) for |x| <= pi + eps: fold to [0, pi/2], then to [0, pi/4] through sin(pi/2 - y). The Taylor coefficients are rationals
211
- // rounded once to float32 (bc: u relative each).
199
+ let t = bmul(z, z);
200
+ var p = bc(1.605904383682161e-10);
201
+ p = badd(bmul(p, t), bc(-2.505210838544172e-8));
202
+ p = badd(bmul(p, t), bc(2.7557319223985893e-6));
203
+ p = badd(bmul(p, t), bc(-0.0001984126984126984));
204
+ p = badd(bmul(p, t), bc(0.008333333333333333));
205
+ p = badd(bmul(p, t), bc(-0.16666666666666666));
206
+ p = badd(bmul(p, t), bc(1.0));
207
+ let s = bmul(p, z);
208
+ return B(s.v, s.e + 2.0e-14);
209
+ }
210
+
211
+
212
212
  fn bcos(x: B) -> B {
213
- var y = babs(x);
214
- var negate = false;
215
- if (y.v > HALF_PI) { y = bsub(bc(PI), y); negate = true; }
216
- var c: B;
217
- if (y.v > QUARTER_PI) { c = bsin_poly(bsub(bc(HALF_PI), y)); } else { c = bcos_poly(y); }
218
- if (negate) { c = bneg(c); }
219
- return c;
213
+ var y = babs(x);
214
+ var negate = false;
215
+ if (y.v > HALF_PI) { y = bsub(bc(PI), y); negate = true; }
216
+ var c: B;
217
+ if (y.v > QUARTER_PI) { c = bsin_poly(bsub(bc(HALF_PI), y)); } else { c = bcos_poly(y); }
218
+ if (negate) { c = bneg(c); }
219
+ return c;
220
220
  }
221
221
 
222
222
  fn bars_material(x: B, origin: f32, w: f32) -> u32 {
223
- let t = bdiv(bsub(x, bc(origin)), bc(w));
224
- let n = bfloor(t, -3.0e38, 3.0e38);
225
- return select(1u, 0u, parity_even(i32(n), 0));
223
+ let t = bdiv(bsub(x, bc(origin)), bc(w));
224
+ let n = bfloor(t, -3.0e38, 3.0e38);
225
+ return select(1u, 0u, parity_even(i32(n), 0));
226
226
  }
227
227
  fn numeral_ink(u: B, v: B, lu0: f32, lv0: f32, h: f32, digits: u32) -> bool {
228
- let x = bdiv(bsub(u, bc(lu0)), bc(h));
229
- let y = bdiv(bsub(v, bc(lv0)), bc(h));
230
- if (lt(y, bx(0.0)) || gt(y, bx(1.0)) || lt(x, bx(0.0))) { return false; }
231
- let count = ai[digits];
232
- let k = bfloor(bdiv(x, bc(NUMERAL_ADVANCE)), 0.0, f32(count));
233
- if (k >= f32(count)) { return false; }
234
- let cx = bsub(x, bmul(bx(k), bc(NUMERAL_ADVANCE)));
235
- let mask = DIGIT_MASK[ai[digits + 1u + u32(k)]];
236
- for (var s = 0u; s < 7u; s++) {
237
- if ((mask & (1u << s)) == 0u) { continue; }
238
- let box = SEGMENT_BOX[s];
239
- if (ge(cx, bc(box.x)) && le(cx, bc(box.z)) && ge(y, bc(box.y)) && le(y, bc(box.w))) { return true; }
240
- }
241
- return false;
242
- }
243
-
244
- // Sign of the cross product of boundary k's direction with the point: >= 0 when the point's angle is at or past the boundary.
228
+ let x = bdiv(bsub(u, bc(lu0)), bc(h));
229
+ let y = bdiv(bsub(v, bc(lv0)), bc(h));
230
+ if (lt(y, bx(0.0)) || gt(y, bx(1.0)) || lt(x, bx(0.0))) { return false; }
231
+ let count = ai[digits];
232
+ let k = bfloor(bdiv(x, bc(NUMERAL_ADVANCE)), 0.0, f32(count));
233
+ if (k >= f32(count)) { return false; }
234
+ let cx = bsub(x, bmul(bx(k), bc(NUMERAL_ADVANCE)));
235
+ let mask = DIGIT_MASK[ai[digits + 1u + u32(k)]];
236
+ for (var s = 0u; s < 7u; s++) {
237
+ if ((mask & (1u << s)) == 0u) { continue; }
238
+ let box = SEGMENT_BOX[s];
239
+ if (ge(cx, bc(box.x)) && le(cx, bc(box.z)) && ge(y, bc(box.y)) && le(y, bc(box.w))) { return true; }
240
+ }
241
+ return false;
242
+ }
243
+
244
+
245
245
  fn star_cross(dirs: u32, k: u32, x: D, y: D) -> B {
246
- let o = dirs + 4u * k;
247
- let cx = D(af[o], af[o + 1u]); let sx = D(af[o + 2u], af[o + 3u]);
248
- return bds(d_sub(d_mul(cx, y), d_mul(sx, x)), abs(cx.h * y.h) + abs(sx.h * x.h));
246
+ let o = dirs + 4u * k;
247
+ let cx = D(af[o], af[o + 1u]); let sx = D(af[o + 2u], af[o + 3u]);
248
+ return bds(d_sub(d_mul(cx, y), d_mul(sx, x)), abs(cx.h * y.h) + abs(sx.h * x.h));
249
249
  }
250
250
 
251
251
  fn classify(kind: u32, ioff: u32, foff: u32, xd: D, yd: D) -> u32 {
252
- let u = bd(xd); let v = bd(yd);
253
- switch (kind) {
254
- case 0u: { return 0u; }
255
- case 1u: {
256
- let d = bsub(bmul(u, bc(af[foff])), bmul(v, bc(af[foff + 1u])));
257
- return select(0u, 1u, ge0(d));
258
- }
259
- case 2u: {
260
- let n = ai[ioff]; let dirs = ai[ioff + 1u]; let levels = ai[ioff + 2u]; let buckets = ai[ioff + 3u]; let m = ai[ioff + 4u]; let w = i32(ai[ioff + 5u]);
261
- let q = bd(d_add(d_mul(xd, xd), d_mul(yd, yd)));
262
- if (gt(q, bc(af[foff]))) { return ai[ioff + 6u]; }
263
- let a = atan2(yd.h, xd.h);
264
- let j = u32(clamp(floor((a + PI) * f32(m) / (2.0 * PI)), 0.0, f32(m - 1u)));
265
- let k0 = i32(ai[buckets + j]);
266
- var lo = k0 - w; var hi = k0 + w + 1;
267
- let ni = i32(n);
268
- let clo = star_cross(dirs, u32((lo % ni + ni) % ni), xd, yd);
269
- let chi = star_cross(dirs, u32((hi % ni + ni) % ni), xd, yd);
270
- if (!ge0(clo) || ge0(chi)) { flagged = true; return 0u; }
271
- for (var step = 0u; step < 32u && hi - lo > 1; step++) {
272
- let mid = (lo + hi) / 2;
273
- let c = star_cross(dirs, u32((mid % ni + ni) % ni), xd, yd);
274
- if (c.v >= 0.0) { lo = mid; } else { hi = mid; }
275
- }
276
- if (hi - lo > 1) { flagged = true; }
277
- let kl = u32((lo % ni + ni) % ni); let kh = u32((hi % ni + ni) % ni);
278
- if (!ge0(star_cross(dirs, kl, xd, yd)) || ge0(star_cross(dirs, kh, xd, yd))) { flagged = true; }
279
- return ai[levels + kl];
280
- }
281
- case 3u: {
282
- let steps = f32(ai[ioff]);
283
- let t = bmul(bmul(badd(u, bx(1.0)), bx(0.5)), bx(steps));
284
- return u32(clamp(bfloor(t, 1.0, steps - 1.0), 0.0, steps - 1.0));
285
- }
286
- case 5u: {
287
- let size = bc(af[foff]); let aspect = bc(af[foff + 1u]);
288
- let i = bfloor(bdiv(badd(u, bx(1.0)), size), -3.0e38, 3.0e38);
289
- let j = bfloor(bdiv(bsub(aspect, v), size), -3.0e38, 3.0e38);
290
- return select(0u, 1u, parity_even(i32(i), i32(j)));
291
- }
292
- case 6u: {
293
- let columns = ai[ioff]; let rows = ai[ioff + 1u]; let centers = ai[ioff + 2u];
294
- let i = u32(clamp(bfloor(bdiv(badd(u, bx(1.0)), bc(af[foff])), 1.0, f32(columns - 1u)), 0.0, f32(columns - 1u)));
295
- let j = u32(clamp(bfloor(bdiv(bsub(bc(af[foff + 2u]), v), bc(af[foff + 1u])), 1.0, f32(rows - 1u)), 0.0, f32(rows - 1u)));
296
- let c = centers + 2u * (j * columns + i);
297
- let dx = bsub(u, bc(af[c])); let dy = bsub(v, bc(af[c + 1u]));
298
- let d2 = badd(bmul(dx, dx), bmul(dy, dy));
299
- return select(0u, 1u, le(d2, bc(af[foff + 3u])));
300
- }
301
- case 7u: {
302
- let columns = ai[ioff]; let rows = ai[ioff + 1u]; let count = ai[ioff + 2u]; let background = ai[ioff + 3u];
303
- let fx = bdiv(badd(u, bx(1.0)), bc(af[foff])); let fy = bdiv(bsub(bc(af[foff + 2u]), v), bc(af[foff + 1u]));
304
- let i = bfloor(fx, -3.0e38, 3.0e38); let j = bfloor(fy, -3.0e38, 3.0e38);
305
- if (i < 0.0 || j < 0.0 || i >= f32(columns) || j >= f32(rows)) { return background; }
306
- let index = u32(j) * columns + u32(i);
307
- let x = bsub(fx, bx(i)); let y = bsub(fy, bx(j));
308
- let g0 = bc(af[foff + 3u]); let g1 = bc(af[foff + 4u]);
309
- if (index >= count || lt(x, g0) || gt(x, g1) || lt(y, g0) || gt(y, g1)) { return background; }
310
- return index;
311
- }
312
- case 8u: {
313
- let nx = ai[ioff]; let ny = ai[ioff + 1u]; let csr = ai[ioff + 2u]; let entries = ai[ioff + 3u]; let disks = ai[ioff + 4u]; let mean = ai[ioff + 5u];
314
- let cell = bc(af[foff + 2u]);
315
- let i = bfloor(bdiv(bsub(u, bc(af[foff])), cell), -3.0e38, 3.0e38);
316
- let j = bfloor(bdiv(bsub(v, bc(af[foff + 1u])), cell), -3.0e38, 3.0e38);
317
- if (i < 0.0 || j < 0.0 || i >= f32(nx) || j >= f32(ny)) { return mean; }
318
- let c = u32(j) * nx + u32(i);
319
- let start = ai[csr + c]; let end = ai[csr + c + 1u];
320
- for (var e = start; e < end; e++) {
321
- let d = disks + 4u * ai[entries + e];
322
- let dx = bsub(u, bc(af[d])); let dy = bsub(v, bc(af[d + 1u]));
323
- let d2 = badd(bmul(dx, dx), bmul(dy, dy));
324
- if (le(d2, bc(af[d + 2u]))) { return u32(af[d + 3u]); }
325
- }
326
- return mean;
327
- }
328
- case 9u: {
329
- let groups = ai[ioff]; let gf = ai[ioff + 1u]; let digits = ai[ioff + 2u];
330
- for (var g = 0u; g < groups; g++) {
252
+ let u = bd(xd); let v = bd(yd);
253
+ switch (kind) {
254
+ case 0u: { return 0u; }
255
+ case 1u: {
256
+ let d = bsub(bmul(u, bc(af[foff])), bmul(v, bc(af[foff + 1u])));
257
+ return select(0u, 1u, ge0(d));
258
+ }
259
+ case 2u: {
260
+ let n = ai[ioff]; let dirs = ai[ioff + 1u]; let levels = ai[ioff + 2u]; let buckets = ai[ioff + 3u]; let m = ai[ioff + 4u]; let w = i32(ai[ioff + 5u]);
261
+ let q = bd(d_add(d_mul(xd, xd), d_mul(yd, yd)));
262
+ if (gt(q, bc(af[foff]))) { return ai[ioff + 6u]; }
263
+ let a = atan2(yd.h, xd.h);
264
+ let j = u32(clamp(floor((a + PI) * f32(m) / (2.0 * PI)), 0.0, f32(m - 1u)));
265
+ let k0 = i32(ai[buckets + j]);
266
+ var lo = k0 - w; var hi = k0 + w + 1;
267
+ let ni = i32(n);
268
+ let clo = star_cross(dirs, u32((lo % ni + ni) % ni), xd, yd);
269
+ let chi = star_cross(dirs, u32((hi % ni + ni) % ni), xd, yd);
270
+ if (!ge0(clo) || ge0(chi)) { flagged = true; return 0u; }
271
+ for (var step = 0u; step < 32u && hi - lo > 1; step++) {
272
+ let mid = (lo + hi) / 2;
273
+ let c = star_cross(dirs, u32((mid % ni + ni) % ni), xd, yd);
274
+ if (c.v >= 0.0) { lo = mid; } else { hi = mid; }
275
+ }
276
+ if (hi - lo > 1) { flagged = true; }
277
+ let kl = u32((lo % ni + ni) % ni); let kh = u32((hi % ni + ni) % ni);
278
+ if (!ge0(star_cross(dirs, kl, xd, yd)) || ge0(star_cross(dirs, kh, xd, yd))) { flagged = true; }
279
+ return ai[levels + kl];
280
+ }
281
+ case 3u: {
282
+ let steps = f32(ai[ioff]);
283
+ let t = bmul(bmul(badd(u, bx(1.0)), bx(0.5)), bx(steps));
284
+ return u32(clamp(bfloor(t, 1.0, steps - 1.0), 0.0, steps - 1.0));
285
+ }
286
+ case 5u: {
287
+ let size = bc(af[foff]); let aspect = bc(af[foff + 1u]);
288
+ let i = bfloor(bdiv(badd(u, bx(1.0)), size), -3.0e38, 3.0e38);
289
+ let j = bfloor(bdiv(bsub(aspect, v), size), -3.0e38, 3.0e38);
290
+ return select(0u, 1u, parity_even(i32(i), i32(j)));
291
+ }
292
+ case 6u: {
293
+ let columns = ai[ioff]; let rows = ai[ioff + 1u]; let centers = ai[ioff + 2u];
294
+ let i = u32(clamp(bfloor(bdiv(badd(u, bx(1.0)), bc(af[foff])), 1.0, f32(columns - 1u)), 0.0, f32(columns - 1u)));
295
+ let j = u32(clamp(bfloor(bdiv(bsub(bc(af[foff + 2u]), v), bc(af[foff + 1u])), 1.0, f32(rows - 1u)), 0.0, f32(rows - 1u)));
296
+ let c = centers + 2u * (j * columns + i);
297
+ let dx = bsub(u, bc(af[c])); let dy = bsub(v, bc(af[c + 1u]));
298
+ let d2 = badd(bmul(dx, dx), bmul(dy, dy));
299
+ return select(0u, 1u, le(d2, bc(af[foff + 3u])));
300
+ }
301
+ case 7u: {
302
+ let columns = ai[ioff]; let rows = ai[ioff + 1u]; let count = ai[ioff + 2u]; let background = ai[ioff + 3u];
303
+ let fx = bdiv(badd(u, bx(1.0)), bc(af[foff])); let fy = bdiv(bsub(bc(af[foff + 2u]), v), bc(af[foff + 1u]));
304
+ let i = bfloor(fx, -3.0e38, 3.0e38); let j = bfloor(fy, -3.0e38, 3.0e38);
305
+ if (i < 0.0 || j < 0.0 || i >= f32(columns) || j >= f32(rows)) { return background; }
306
+ let index = u32(j) * columns + u32(i);
307
+ let x = bsub(fx, bx(i)); let y = bsub(fy, bx(j));
308
+ let g0 = bc(af[foff + 3u]); let g1 = bc(af[foff + 4u]);
309
+ if (index >= count || lt(x, g0) || gt(x, g1) || lt(y, g0) || gt(y, g1)) { return background; }
310
+ return index;
311
+ }
312
+ case 8u: {
313
+ let nx = ai[ioff]; let ny = ai[ioff + 1u]; let csr = ai[ioff + 2u]; let entries = ai[ioff + 3u]; let disks = ai[ioff + 4u]; let mean = ai[ioff + 5u];
314
+ let cell = bc(af[foff + 2u]);
315
+ let i = bfloor(bdiv(bsub(u, bc(af[foff])), cell), -3.0e38, 3.0e38);
316
+ let j = bfloor(bdiv(bsub(v, bc(af[foff + 1u])), cell), -3.0e38, 3.0e38);
317
+ if (i < 0.0 || j < 0.0 || i >= f32(nx) || j >= f32(ny)) { return mean; }
318
+ let c = u32(j) * nx + u32(i);
319
+ let start = ai[csr + c]; let end = ai[csr + c + 1u];
320
+ for (var e = start; e < end; e++) {
321
+ let d = disks + 4u * ai[entries + e];
322
+ let dx = bsub(u, bc(af[d])); let dy = bsub(v, bc(af[d + 1u]));
323
+ let d2 = badd(bmul(dx, dx), bmul(dy, dy));
324
+ if (le(d2, bc(af[d + 2u]))) { return u32(af[d + 3u]); }
325
+ }
326
+ return mean;
327
+ }
328
+ case 9u: {
329
+ let groups = ai[ioff]; let gf = ai[ioff + 1u]; let digits = ai[ioff + 2u];
330
+ for (var g = 0u; g < groups; g++) {
331
331
  let o = gf + ${CHART_RECORD_STRIDE.barGroupFloats}u * g;
332
- if (lt(u, bc(af[o])) || gt(u, bc(af[o + 1u]))) { continue; }
333
- if (ge(u, bc(af[o + 2u])) && lt(u, bc(af[o + 4u])) && ge(v, bc(af[o + 3u])) && le(v, bc(af[o + 5u]))) { return bars_material(u, af[o + 2u], af[o + 10u]); }
334
- if (ge(u, bc(af[o + 6u])) && le(u, bc(af[o + 8u])) && gt(v, bc(af[o + 7u])) && le(v, bc(af[o + 9u]))) {
335
- let t = bdiv(bsub(bc(af[o + 9u]), v), bc(af[o + 10u]));
336
- let n = bfloor(t, -3.0e38, 3.0e38);
337
- return select(1u, 0u, parity_even(i32(n), 0));
338
- }
339
- if (af[o + 11u] != 0.0 && numeral_ink(u, v, af[o + 12u], af[o + 13u], af[o + 14u], digits + u32(af[o + 15u]))) { return 0u; }
340
- return 1u;
341
- }
342
- return 1u;
343
- }
344
- case 10u: {
345
- let horizontal = ai[ioff] == 0u; let lines = f32(ai[ioff + 1u]);
346
- var s: B; var y: B;
347
- if (horizontal) { s = bmul(badd(u, bx(1.0)), bx(0.5)); y = v; } else { s = bdiv(badd(v, bc(af[foff])), bc(af[foff + 4u])); y = u; }
348
- if (lt(s, bx(0.0)) || gt(s, bx(1.0))) { return 1u; }
349
- let w = bdiv(bc(af[foff + 1u]), badd(bc(af[foff + 2u]), bmul(bc(af[foff + 3u]), s)));
350
- let half = bmul(w, bx((2.0 * lines - 1.0) * 0.5));
351
- if (lt(y, bneg(half)) || ge(y, half)) { return 1u; }
352
- let n = bfloor(bdiv(badd(y, half), w), -3.0e38, 3.0e38);
353
- return select(1u, 0u, parity_even(i32(n), 0));
354
- }
355
- case 11u: {
356
- let q = d_add(d_mul(xd, xd), d_mul(yd, yd));
357
- if (gt(bd(q), bc(af[foff]))) { return 1024u; }
358
- let psi = d_mul(q, D(af[foff + 1u], af[foff + 2u]));
359
- if (!(abs(psi.h) < 1048576.0)) { flagged = true; return 0u; }
360
- let n = 2.0 * round(psi.h * 0.5);
361
- let r = (psi.h - n) + psi.l;
362
- let phase = B(r, DW * (abs(psi.h) + abs(psi.l)) + E * abs(r) + TINY);
363
- let c = bcos(bmul(bc(PI), phase));
364
- let t = bmul(bx(512.0), badd(bx(1.0), c));
365
- return u32(clamp(bfloor(t, 1.0, 1023.0), 0.0, 1023.0));
366
- }
367
- case 12u: {
368
- let columns = ai[ioff]; let rows = ai[ioff + 1u];
369
- let cellW = bc(af[foff]); let cellH = bc(af[foff + 1u]); let aspect = bc(af[foff + 2u]);
370
- let i = clamp(bfloor(bdiv(badd(u, bx(1.0)), cellW), 1.0, f32(columns - 1u)), 0.0, f32(columns - 1u));
371
- let j = clamp(bfloor(bdiv(bsub(aspect, v), cellH), 1.0, f32(rows - 1u)), 0.0, f32(rows - 1u));
372
- let du = bsub(u, badd(bx(-1.0), bmul(bx(i + 0.5), cellW)));
373
- let dv = bsub(v, bsub(aspect, bmul(bx(j + 0.5), cellH)));
374
- let c = bc(af[foff + 3u]); let s = bc(af[foff + 4u]); let half = bc(af[foff + 5u]);
375
- let x = bsub(bmul(du, c), bmul(dv, s)); let y = badd(bmul(du, s), bmul(dv, c));
376
- return select(1u, 0u, le(babs(x), half) && le(babs(y), half));
377
- }
378
- case 13u: {
379
- let spacing = bc(af[foff]); let half = bc(af[foff + 1u]);
380
- let nu = round(u.v / spacing.v); let nv = round(v.v / spacing.v);
381
- let du = babs(bsub(u, bmul(spacing, bx(nu)))); let dv = babs(bsub(v, bmul(spacing, bx(nv))));
382
- return select(0u, 1u, le(du, half) || le(dv, half));
383
- }
384
- case 14u: {
385
- let inverted = ai[ioff] != 0u;
386
- let q = badd(bmul(u, u), bmul(v, v));
387
- if (gt(q, bc(af[foff]))) { return 2u; }
388
- if (gt(q, bc(af[foff + 1u]))) { return 0u; }
389
- let same = ge0(u) == ge0(v);
390
- return select(1u, 0u, same != inverted);
391
- }
392
- default: { flagged = true; return 0u; }
393
- }
394
- }
395
-
396
- // Whether the point (mask units, bounded) is inside the shape; a point outside the bounding box by more than its margin is not.
332
+ if (lt(u, bc(af[o])) || gt(u, bc(af[o + 1u]))) { continue; }
333
+ if (ge(u, bc(af[o + 2u])) && lt(u, bc(af[o + 4u])) && ge(v, bc(af[o + 3u])) && le(v, bc(af[o + 5u]))) { return bars_material(u, af[o + 2u], af[o + 10u]); }
334
+ if (ge(u, bc(af[o + 6u])) && le(u, bc(af[o + 8u])) && gt(v, bc(af[o + 7u])) && le(v, bc(af[o + 9u]))) {
335
+ let t = bdiv(bsub(bc(af[o + 9u]), v), bc(af[o + 10u]));
336
+ let n = bfloor(t, -3.0e38, 3.0e38);
337
+ return select(1u, 0u, parity_even(i32(n), 0));
338
+ }
339
+ if (af[o + 11u] != 0.0 && numeral_ink(u, v, af[o + 12u], af[o + 13u], af[o + 14u], digits + u32(af[o + 15u]))) { return 0u; }
340
+ return 1u;
341
+ }
342
+ return 1u;
343
+ }
344
+ case 10u: {
345
+ let horizontal = ai[ioff] == 0u; let lines = f32(ai[ioff + 1u]);
346
+ var s: B; var y: B;
347
+ if (horizontal) { s = bmul(badd(u, bx(1.0)), bx(0.5)); y = v; } else { s = bdiv(badd(v, bc(af[foff])), bc(af[foff + 4u])); y = u; }
348
+ if (lt(s, bx(0.0)) || gt(s, bx(1.0))) { return 1u; }
349
+ let w = bdiv(bc(af[foff + 1u]), badd(bc(af[foff + 2u]), bmul(bc(af[foff + 3u]), s)));
350
+ let half = bmul(w, bx((2.0 * lines - 1.0) * 0.5));
351
+ if (lt(y, bneg(half)) || ge(y, half)) { return 1u; }
352
+ let n = bfloor(bdiv(badd(y, half), w), -3.0e38, 3.0e38);
353
+ return select(1u, 0u, parity_even(i32(n), 0));
354
+ }
355
+ case 11u: {
356
+ let q = d_add(d_mul(xd, xd), d_mul(yd, yd));
357
+ if (gt(bd(q), bc(af[foff]))) { return 1024u; }
358
+ let psi = d_mul(q, D(af[foff + 1u], af[foff + 2u]));
359
+ if (!(abs(psi.h) < 1048576.0)) { flagged = true; return 0u; }
360
+ let n = 2.0 * round(psi.h * 0.5);
361
+ let r = (psi.h - n) + psi.l;
362
+ let phase = B(r, DW * (abs(psi.h) + abs(psi.l)) + E * abs(r) + TINY);
363
+ let c = bcos(bmul(bc(PI), phase));
364
+ let t = bmul(bx(512.0), badd(bx(1.0), c));
365
+ return u32(clamp(bfloor(t, 1.0, 1023.0), 0.0, 1023.0));
366
+ }
367
+ case 12u: {
368
+ let columns = ai[ioff]; let rows = ai[ioff + 1u];
369
+ let cellW = bc(af[foff]); let cellH = bc(af[foff + 1u]); let aspect = bc(af[foff + 2u]);
370
+ let i = clamp(bfloor(bdiv(badd(u, bx(1.0)), cellW), 1.0, f32(columns - 1u)), 0.0, f32(columns - 1u));
371
+ let j = clamp(bfloor(bdiv(bsub(aspect, v), cellH), 1.0, f32(rows - 1u)), 0.0, f32(rows - 1u));
372
+ let du = bsub(u, badd(bx(-1.0), bmul(bx(i + 0.5), cellW)));
373
+ let dv = bsub(v, bsub(aspect, bmul(bx(j + 0.5), cellH)));
374
+ let c = bc(af[foff + 3u]); let s = bc(af[foff + 4u]); let half = bc(af[foff + 5u]);
375
+ let x = bsub(bmul(du, c), bmul(dv, s)); let y = badd(bmul(du, s), bmul(dv, c));
376
+ return select(1u, 0u, le(babs(x), half) && le(babs(y), half));
377
+ }
378
+ case 13u: {
379
+ let spacing = bc(af[foff]); let half = bc(af[foff + 1u]);
380
+ let nu = round(u.v / spacing.v); let nv = round(v.v / spacing.v);
381
+ let du = babs(bsub(u, bmul(spacing, bx(nu)))); let dv = babs(bsub(v, bmul(spacing, bx(nv))));
382
+ return select(0u, 1u, le(du, half) || le(dv, half));
383
+ }
384
+ case 14u: {
385
+ let inverted = ai[ioff] != 0u;
386
+ let q = badd(bmul(u, u), bmul(v, v));
387
+ if (gt(q, bc(af[foff]))) { return 2u; }
388
+ if (gt(q, bc(af[foff + 1u]))) { return 0u; }
389
+ let same = ge0(u) == ge0(v);
390
+ return select(1u, 0u, same != inverted);
391
+ }
392
+ default: { flagged = true; return 0u; }
393
+ }
394
+ }
395
+
396
+
397
397
  fn shape_contains(shape: u32, x: B, y: B) -> bool {
398
- let kind = ai[shape]; let data = ai[shape + 1u]; let edges = ai[shape + 2u];
399
- let mx = margin(x); let my = margin(y);
400
- if (x.v + mx < af[data] || x.v - mx > af[data + 2u] || y.v + my < af[data + 1u] || y.v - my > af[data + 3u]) { return false; }
401
- if (kind == 1u) {
402
- let dx = bsub(x, bc(af[data + 4u])); let dy = bsub(y, bc(af[data + 5u]));
403
- let d2 = badd(bmul(dx, dx), bmul(dy, dy));
404
- return ge(d2, bc(af[data + 6u])) && le(d2, bc(af[data + 7u]));
405
- }
406
- var winding = 0;
407
- for (var k = 0u; k < edges; k++) {
408
- let o = data + 4u + 4u * k;
409
- let x0 = bc(af[o]); let y0 = bc(af[o + 1u]); let x1 = bc(af[o + 2u]); let y1 = bc(af[o + 3u]);
410
- if (ge(y, y0)) {
411
- if (gt(y1, y)) {
412
- let side = bsub(bmul(bsub(x1, x0), bsub(y, y0)), bmul(bsub(x, x0), bsub(y1, y0)));
413
- if (gt(side, bx(0.0))) { winding = winding + 1; }
414
- }
415
- } else if (le(y1, y)) {
416
- let side = bsub(bmul(bsub(x1, x0), bsub(y, y0)), bmul(bsub(x, x0), bsub(y1, y0)));
417
- if (lt(side, bx(0.0))) { winding = winding - 1; }
418
- }
419
- }
420
- return winding != 0;
421
- }
422
-
423
- // The material of a point: the topmost layer holding it, else the topmost element holding it, else the background.
398
+ let kind = ai[shape]; let data = ai[shape + 1u]; let edges = ai[shape + 2u];
399
+ let mx = margin(x); let my = margin(y);
400
+ if (x.v + mx < af[data] || x.v - mx > af[data + 2u] || y.v + my < af[data + 1u] || y.v - my > af[data + 3u]) { return false; }
401
+ if (kind == 1u) {
402
+ let dx = bsub(x, bc(af[data + 4u])); let dy = bsub(y, bc(af[data + 5u]));
403
+ let d2 = badd(bmul(dx, dx), bmul(dy, dy));
404
+ return ge(d2, bc(af[data + 6u])) && le(d2, bc(af[data + 7u]));
405
+ }
406
+ var winding = 0;
407
+ for (var k = 0u; k < edges; k++) {
408
+ let o = data + 4u + 4u * k;
409
+ let x0 = bc(af[o]); let y0 = bc(af[o + 1u]); let x1 = bc(af[o + 2u]); let y1 = bc(af[o + 3u]);
410
+ if (ge(y, y0)) {
411
+ if (gt(y1, y)) {
412
+ let side = bsub(bmul(bsub(x1, x0), bsub(y, y0)), bmul(bsub(x, x0), bsub(y1, y0)));
413
+ if (gt(side, bx(0.0))) { winding = winding + 1; }
414
+ }
415
+ } else if (le(y1, y)) {
416
+ let side = bsub(bmul(bsub(x1, x0), bsub(y, y0)), bmul(bsub(x, x0), bsub(y1, y0)));
417
+ if (lt(side, bx(0.0))) { winding = winding - 1; }
418
+ }
419
+ }
420
+ return winding != 0;
421
+ }
422
+
423
+
424
424
  fn material(p: vec4<f32>) -> u32 {
425
- let ud = D(p.x, p.y); let vd = D(p.z, p.w);
426
- let u = bd(ud); let v = bd(vd);
427
- let layers = ai[1]; let hl = ai[3];
428
- for (var l = layers; l > 0u; l--) {
425
+ let ud = D(p.x, p.y); let vd = D(p.z, p.w);
426
+ let u = bd(ud); let v = bd(vd);
427
+ let layers = ai[1]; let hl = ai[3];
428
+ for (var l = layers; l > 0u; l--) {
429
429
  let h = hl + ${CHART_RECORD_STRIDE.layer}u * (l - 1u);
430
- let f = ai[h + 6u];
431
- let u0 = bc(af[f]); let v0 = bc(af[f + 1u]); let u1 = bc(af[f + 2u]); let v1 = bc(af[f + 3u]);
432
- if (lt(u, u0) || gt(u, u1) || lt(v, v0) || gt(v, v1)) { continue; }
433
- let x = bmul(bsub(u, u0), bc(af[f + 4u])); let y = bmul(bsub(v1, v), bc(af[f + 5u]));
434
- let cellsX = ai[h]; let cellsY = ai[h + 1u];
435
- let i = u32(clamp(floor(x.v / af[f + 6u]), 0.0, f32(cellsX - 1u)));
436
- let j = u32(clamp(floor(y.v / af[f + 7u]), 0.0, f32(cellsY - 1u)));
437
- let cell = j * cellsX + i;
438
- let start = ai[ai[h + 2u] + cell]; let end = ai[ai[h + 2u] + cell + 1u];
439
- for (var e = start; e < end; e++) {
430
+ let f = ai[h + 6u];
431
+ let u0 = bc(af[f]); let v0 = bc(af[f + 1u]); let u1 = bc(af[f + 2u]); let v1 = bc(af[f + 3u]);
432
+ if (lt(u, u0) || gt(u, u1) || lt(v, v0) || gt(v, v1)) { continue; }
433
+ let x = bmul(bsub(u, u0), bc(af[f + 4u])); let y = bmul(bsub(v1, v), bc(af[f + 5u]));
434
+ let cellsX = ai[h]; let cellsY = ai[h + 1u];
435
+ let i = u32(clamp(floor(x.v / af[f + 6u]), 0.0, f32(cellsX - 1u)));
436
+ let j = u32(clamp(floor(y.v / af[f + 7u]), 0.0, f32(cellsY - 1u)));
437
+ let cell = j * cellsX + i;
438
+ let start = ai[ai[h + 2u] + cell]; let end = ai[ai[h + 2u] + cell + 1u];
439
+ for (var e = start; e < end; e++) {
440
440
  let shape = ai[h + 4u] + ${CHART_RECORD_STRIDE.shape}u * ai[ai[h + 3u] + e];
441
- if (shape_contains(shape, x, y)) { return ai[h + 8u]; }
442
- }
443
- return ai[h + 7u];
444
- }
445
- let elements = ai[0]; let he = ai[2];
446
- for (var i = elements; i > 0u; i--) {
441
+ if (shape_contains(shape, x, y)) { return ai[h + 8u]; }
442
+ }
443
+ return ai[h + 7u];
444
+ }
445
+ let elements = ai[0]; let he = ai[2];
446
+ for (var i = elements; i > 0u; i--) {
447
447
  let h = he + ${CHART_RECORD_STRIDE.element}u * (i - 1u);
448
- let kind = ai[h]; let offset = ai[h + 1u]; let ioff = ai[h + 2u]; let foff = ai[h + 3u]; let placement = ai[h + 4u];
448
+ let kind = ai[h]; let offset = ai[h + 1u]; let ioff = ai[h + 2u]; let foff = ai[h + 3u]; let placement = ai[h + 4u];
449
449
  if (placement == ${CHART_PLACEMENT.frame}u) { return offset + classify(kind, ioff, foff + ${CHART_RECORD_STRIDE.placementFloats}u, ud, vd); }
450
- let du = d_sub(ud, D(af[foff], af[foff + 1u])); let dv = d_sub(vd, D(af[foff + 2u], af[foff + 3u]));
451
- let hw = bc(af[foff + 4u]); let hh = bc(af[foff + 5u]);
452
- let bu = bds(du, abs(ud.h) + abs(af[foff])); let bv = bds(dv, abs(vd.h) + abs(af[foff + 2u]));
453
- if (lt(bu, bneg(hw)) || gt(bu, hw) || lt(bv, bneg(hh)) || gt(bv, hh)) { continue; }
450
+ let du = d_sub(ud, D(af[foff], af[foff + 1u])); let dv = d_sub(vd, D(af[foff + 2u], af[foff + 3u]));
451
+ let hw = bc(af[foff + 4u]); let hh = bc(af[foff + 5u]);
452
+ let bu = bds(du, abs(ud.h) + abs(af[foff])); let bv = bds(dv, abs(vd.h) + abs(af[foff + 2u]));
453
+ if (lt(bu, bneg(hw)) || gt(bu, hw) || lt(bv, bneg(hh)) || gt(bv, hh)) { continue; }
454
454
  if (placement == ${CHART_PLACEMENT.ellipse}u) {
455
- let a = bdiv(bu, hw); let b = bdiv(bv, hh);
456
- if (gt(badd(bmul(a, a), bmul(b, b)), bx(1.0))) { continue; }
457
- }
458
- let scale = D(af[foff + 6u], af[foff + 7u]);
455
+ let a = bdiv(bu, hw); let b = bdiv(bv, hh);
456
+ if (gt(badd(bmul(a, a), bmul(b, b)), bx(1.0))) { continue; }
457
+ }
458
+ let scale = D(af[foff + 6u], af[foff + 7u]);
459
459
  return offset + classify(kind, ioff, foff + ${CHART_RECORD_STRIDE.placementFloats}u, d_mul(du, scale), d_mul(dv, scale));
460
- }
461
- flagged = true;
462
- return 0u;
460
+ }
461
+ flagged = true;
462
+ return 0u;
463
463
  }
464
464
 
465
465
  @compute @workgroup_size(${CHART_COMPOSITE_WORKGROUP_SIZE})
466
466
  fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) groups: vec3<u32>) {
467
467
  let i = gid.x + gid.y * groups.x * ${CHART_COMPOSITE_WORKGROUP_SIZE}u;
468
- if (i >= params.count) { return; }
469
- flagged = false;
470
- let m = material(points[i]);
471
- if (params.wavelength_mode != 0u) {
472
- values[i] = table[m * params.columns + selectors[i]];
473
- } else {
474
- for (var c = 0u; c < params.columns; c++) { values[i * params.columns + c] = table[m * params.columns + c]; }
475
- }
476
- flags[i] = select(0u, 1u, flagged);
468
+ if (i >= params.count) { return; }
469
+ flagged = false;
470
+ let m = material(points[i]);
471
+ if (params.wavelength_mode != 0u) {
472
+ values[i] = table[m * params.columns + selectors[i]];
473
+ } else {
474
+ for (var c = 0u; c < params.columns; c++) { values[i * params.columns + c] = table[m * params.columns + c]; }
475
+ }
476
+ flags[i] = select(0u, 1u, flagged);
477
477
  }
478
478
  `;
479
479
  }
@@ -489,21 +489,21 @@ export const CHART_COMPOSITE_WGSL = chartCompositeWgsl("dekker");
489
489
  export const CHART_COMPOSITE_PROBE_WGSL = /* wgsl */ `${commonWgsl("dekker", "probe_zero.x")}
490
490
  @group(0) @binding(0) var<storage, read> input: array<vec4<f32>>;
491
491
  @group(0) @binding(1) var<storage, read_write> output: array<vec4<f32>>;
492
- // x: 0, set by the host; the rounding barrier's word.
492
+
493
493
  @group(0) @binding(2) var<uniform> probe_zero: vec4<u32>;
494
494
  @compute @workgroup_size(1)
495
495
  fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
496
- let i = gid.x;
497
- if (i >= arrayLength(&input)) { return; }
498
- let p = input[i];
499
- let s = two_sum(p.x, p.y);
500
- let m = two_prod_dekker(p.x, p.y);
501
- let a = d_add(D(p.x, p.y), D(p.z, p.w));
502
- let mf = two_prod_fma(p.x, p.y);
503
- let q = d_mul_dekker(D(p.x, p.y), D(p.z, p.w));
504
- let qf = d_mul_fma(D(p.x, p.y), D(p.z, p.w));
505
- output[2u * i] = vec4<f32>(s.l, m.l, a.l, mf.l);
506
- output[2u * i + 1u] = vec4<f32>(q.h, q.l, qf.h, qf.l);
496
+ let i = gid.x;
497
+ if (i >= arrayLength(&input)) { return; }
498
+ let p = input[i];
499
+ let s = two_sum(p.x, p.y);
500
+ let m = two_prod_dekker(p.x, p.y);
501
+ let a = d_add(D(p.x, p.y), D(p.z, p.w));
502
+ let mf = two_prod_fma(p.x, p.y);
503
+ let q = d_mul_dekker(D(p.x, p.y), D(p.z, p.w));
504
+ let qf = d_mul_fma(D(p.x, p.y), D(p.z, p.w));
505
+ output[2u * i] = vec4<f32>(s.l, m.l, a.l, mf.l);
506
+ output[2u * i + 1u] = vec4<f32>(q.h, q.l, qf.h, qf.l);
507
507
  }
508
508
  `;
509
509
  /** Floats the probe writes per input (two vec4). */