@jbrowse/render-core 5.0.0-beta.13 → 5.0.0-beta.14

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 (153) hide show
  1. package/esm/OverlayCanvas.d.ts +3 -2
  2. package/esm/OverlayCanvas.js +4 -2
  3. package/esm/RenderCanvas.d.ts +4 -3
  4. package/esm/RenderCanvas.js +4 -2
  5. package/esm/ScrollLockedOverlay.d.ts +2 -2
  6. package/esm/ScrollLockedOverlay.js +3 -2
  7. package/esm/blockClipUtils.d.ts +5 -5
  8. package/esm/blockClipUtils.js +4 -3
  9. package/esm/canvas2dUtils.d.ts +15 -21
  10. package/esm/canvas2dUtils.js +25 -55
  11. package/esm/colorRampLut.d.ts +2 -2
  12. package/esm/colorRampLut.js +2 -2
  13. package/esm/coverageBand.d.ts +0 -1
  14. package/esm/coverageBand.js +0 -5
  15. package/esm/coverageBandBuffers.d.ts +8 -5
  16. package/esm/createRenderingBackend.d.ts +1 -1
  17. package/esm/displayPhase.d.ts +5 -9
  18. package/esm/displayPhase.js +2 -2
  19. package/esm/hal/mockHal.d.ts +3 -4
  20. package/esm/hal/mockHal.js +5 -4
  21. package/esm/hal/types.d.ts +5 -5
  22. package/esm/hal/webgl2Hal.d.ts +4 -1
  23. package/esm/hal/webgl2Hal.js +15 -6
  24. package/esm/hal/webgpuHal.js +2 -2
  25. package/esm/linkFeet.d.ts +4 -0
  26. package/esm/linkFeet.js +7 -0
  27. package/esm/marks/barMark.d.ts +1 -1
  28. package/esm/marks/colorFill.d.ts +4 -4
  29. package/esm/marks/colorFill.js +4 -4
  30. package/esm/marks/connectorMark.d.ts +48 -0
  31. package/esm/marks/connectorMark.js +285 -0
  32. package/esm/marks/drawAgainstHit.d.ts +1 -1
  33. package/esm/marks/drawAgainstHit.js +4 -4
  34. package/esm/marks/glyphPaint.d.ts +5 -4
  35. package/esm/marks/glyphPaint.js +17 -7
  36. package/esm/marks/index.d.ts +6 -3
  37. package/esm/marks/index.js +5 -3
  38. package/esm/marks/lineMark.d.ts +44 -10
  39. package/esm/marks/lineMark.js +20 -19
  40. package/esm/marks/linkMark.d.ts +22 -5
  41. package/esm/marks/linkMark.js +103 -25
  42. package/esm/marks/markBackend.d.ts +1 -1
  43. package/esm/marks/markBackend.js +1 -1
  44. package/esm/marks/markRamp.d.ts +11 -11
  45. package/esm/marks/markRamp.js +9 -9
  46. package/esm/marks/pointMark.d.ts +11 -5
  47. package/esm/marks/pointMark.js +34 -9
  48. package/esm/marks/rowLane.d.ts +3 -3
  49. package/esm/marks/rowLane.js +2 -2
  50. package/esm/marks/rowTable.d.ts +5 -5
  51. package/esm/marks/rowTable.js +4 -4
  52. package/esm/marks/ruleMark.js +1 -0
  53. package/esm/marks/spanMark.d.ts +4 -4
  54. package/esm/marks/types.d.ts +4 -4
  55. package/esm/marks/types.js +5 -0
  56. package/esm/perRegionRenderingBackend.d.ts +1 -1
  57. package/esm/perRegionRenderingBackend.js +1 -1
  58. package/esm/regionDataMap.d.ts +2 -2
  59. package/esm/regionDataMap.js +2 -2
  60. package/esm/shaders/capsule.js.generated.d.ts +1 -1
  61. package/esm/shaders/capsule.js.generated.js +2 -2
  62. package/esm/shaders/connectorMark.consts.generated.d.ts +11 -0
  63. package/esm/shaders/connectorMark.consts.generated.js +13 -0
  64. package/esm/shaders/{coverageIndicator.generated.d.ts → connectorMark.generated.d.ts} +2 -1
  65. package/esm/shaders/connectorMark.generated.js +8 -0
  66. package/esm/shaders/connectorMark.glsl.generated.d.ts +2 -0
  67. package/esm/shaders/connectorMark.glsl.generated.js +4 -0
  68. package/esm/shaders/connectorMark.iface.generated.d.ts +88 -0
  69. package/esm/shaders/connectorMark.iface.generated.js +1194 -0
  70. package/esm/shaders/connectorMark.js.generated.d.ts +5 -0
  71. package/esm/shaders/connectorMark.js.generated.js +47 -0
  72. package/esm/shaders/connectorMark.wgsl.generated.d.ts +1 -0
  73. package/esm/shaders/connectorMark.wgsl.generated.js +3 -0
  74. package/esm/shaders/coverageInterbase.glsl.generated.d.ts +1 -1
  75. package/esm/shaders/coverageInterbase.glsl.generated.js +1 -1
  76. package/esm/shaders/coverageInterbase.wgsl.generated.d.ts +1 -1
  77. package/esm/shaders/coverageInterbase.wgsl.generated.js +1 -1
  78. package/esm/shaders/curveDistance.js.generated.d.ts +3 -0
  79. package/esm/shaders/curveDistance.js.generated.js +104 -0
  80. package/esm/shaders/lineCenterMark.glsl.generated.d.ts +2 -2
  81. package/esm/shaders/lineCenterMark.glsl.generated.js +2 -2
  82. package/esm/shaders/lineCenterMark.wgsl.generated.d.ts +1 -1
  83. package/esm/shaders/lineCenterMark.wgsl.generated.js +1 -1
  84. package/esm/shaders/linkMark.consts.generated.d.ts +1 -0
  85. package/esm/shaders/linkMark.consts.generated.js +1 -0
  86. package/esm/shaders/linkMark.glsl.generated.d.ts +2 -2
  87. package/esm/shaders/linkMark.glsl.generated.js +2 -2
  88. package/esm/shaders/linkMark.js.generated.d.ts +2 -1
  89. package/esm/shaders/linkMark.js.generated.js +30 -1
  90. package/esm/shaders/linkMark.wgsl.generated.d.ts +1 -1
  91. package/esm/shaders/linkMark.wgsl.generated.js +1 -1
  92. package/esm/shaders/pointMark.glsl.generated.d.ts +1 -1
  93. package/esm/shaders/pointMark.glsl.generated.js +1 -1
  94. package/esm/shaders/pointMark.iface.generated.d.ts +10 -8
  95. package/esm/shaders/pointMark.iface.generated.js +18 -16
  96. package/esm/shaders/pointMark.wgsl.generated.d.ts +1 -1
  97. package/esm/shaders/pointMark.wgsl.generated.js +1 -1
  98. package/package.json +7 -4
  99. package/src/shaders/arcHull.test.ts +87 -0
  100. package/src/shaders/barMark.slang +2 -2
  101. package/src/shaders/capsule.js.generated.ts +2 -2
  102. package/src/shaders/capsule.slang +69 -24
  103. package/src/shaders/clipStrip.slang +1 -1
  104. package/src/shaders/colorPack.slang +2 -2
  105. package/src/shaders/colorRampLut.slang +7 -7
  106. package/src/shaders/connectorMark.consts.generated.ts +24 -0
  107. package/src/shaders/connectorMark.generated.ts +12 -0
  108. package/src/shaders/connectorMark.glsl.generated.ts +6 -0
  109. package/src/shaders/connectorMark.iface.generated.ts +1270 -0
  110. package/src/shaders/connectorMark.js.generated.ts +52 -0
  111. package/src/shaders/connectorMark.slang +287 -0
  112. package/src/shaders/connectorMark.wgsl.generated.ts +4 -0
  113. package/src/shaders/coverageBand.slang +10 -12
  114. package/src/shaders/coverageInterbase.glsl.generated.ts +1 -1
  115. package/src/shaders/coverageInterbase.slang +24 -21
  116. package/src/shaders/coverageInterbase.wgsl.generated.ts +1 -1
  117. package/src/shaders/coverageSnp.slang +1 -1
  118. package/src/shaders/curveDistance.js.generated.ts +100 -0
  119. package/src/shaders/curveDistance.slang +104 -1
  120. package/src/shaders/farDome.test.ts +117 -0
  121. package/src/shaders/hpClampFloor.test.ts +0 -4
  122. package/src/shaders/lineCenterMark.glsl.generated.ts +2 -2
  123. package/src/shaders/lineCenterMark.slang +14 -22
  124. package/src/shaders/lineCenterMark.wgsl.generated.ts +1 -1
  125. package/src/shaders/lineCommon.slang +10 -10
  126. package/src/shaders/lineStepMark.slang +5 -5
  127. package/src/shaders/linkMark.consts.generated.ts +2 -0
  128. package/src/shaders/linkMark.glsl.generated.ts +2 -2
  129. package/src/shaders/linkMark.js.generated.ts +27 -1
  130. package/src/shaders/linkMark.slang +58 -18
  131. package/src/shaders/linkMark.wgsl.generated.ts +1 -1
  132. package/src/shaders/markColor.slang +10 -10
  133. package/src/shaders/pointMark.glsl.generated.ts +1 -1
  134. package/src/shaders/pointMark.iface.generated.ts +19 -16
  135. package/src/shaders/pointMark.slang +12 -8
  136. package/src/shaders/pointMark.wgsl.generated.ts +1 -1
  137. package/src/shaders/rowRect.slang +3 -3
  138. package/src/shaders/rowTable.slang +7 -7
  139. package/src/shaders/scoreScale.slang +1 -1
  140. package/src/shaders/spanMark.slang +5 -5
  141. package/src/shaders/viewRegion.slang +13 -0
  142. package/esm/shaders/coverageIndicator.generated.js +0 -7
  143. package/esm/shaders/coverageIndicator.glsl.generated.d.ts +0 -2
  144. package/esm/shaders/coverageIndicator.glsl.generated.js +0 -4
  145. package/esm/shaders/coverageIndicator.iface.generated.d.ts +0 -85
  146. package/esm/shaders/coverageIndicator.iface.generated.js +0 -114
  147. package/esm/shaders/coverageIndicator.wgsl.generated.d.ts +0 -1
  148. package/esm/shaders/coverageIndicator.wgsl.generated.js +0 -3
  149. package/src/shaders/coverageIndicator.generated.ts +0 -11
  150. package/src/shaders/coverageIndicator.glsl.generated.ts +0 -6
  151. package/src/shaders/coverageIndicator.iface.generated.ts +0 -172
  152. package/src/shaders/coverageIndicator.slang +0 -61
  153. package/src/shaders/coverageIndicator.wgsl.generated.ts +0 -4
@@ -0,0 +1,52 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from connectorMark.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ // Scalar twins of connectorMark.slang, transliterated from slangc's WGSL so
5
+ // the Canvas2D and SVG paths run the shader's own math. See adr-051.
6
+
7
+ function _max(a: number, b: number) {
8
+ return b > a || Number.isNaN(a) ? b : a
9
+ }
10
+
11
+ function _min(a: number, b: number) {
12
+ return b < a || Number.isNaN(a) ? b : a
13
+ }
14
+
15
+ export function connectorBudgetPx(dx: number, dy: number): number {
16
+ let _t0 = _min(Math.abs(dy), 150.0)
17
+ return (Math.sqrt(((dx * dx) + (_t0 * _t0))) * 0.30000001192092896)
18
+ }
19
+
20
+ export function connectorHandlePx(budget: number, maxHandlePx: number): number {
21
+ return _min(maxHandlePx, budget)
22
+ }
23
+
24
+ export function connectorLiftPx(budget: number, dy: number, bend: number): number {
25
+ let _t0: number
26
+ if ((bend < -1.00000001504746622e+29)) {
27
+ _t0 = _min(budget, _max(0.0, (30.0 - Math.abs(dy))))
28
+ } else {
29
+ _t0 = (-_min(bend, 110.0) / 0.75)
30
+ }
31
+ return _t0
32
+ }
33
+
34
+ export function connectorTangent(strand: number, leading: number, reversed: number): number {
35
+ let _t0: number
36
+ if ((leading != 0.0)) {
37
+ _t0 = -1.0
38
+ } else {
39
+ _t0 = 1.0
40
+ }
41
+ let _t1 = (strand * _t0)
42
+ if ((reversed != 0.0)) {
43
+ _t0 = -1.0
44
+ } else {
45
+ _t0 = 1.0
46
+ }
47
+ return (_t1 * _t0)
48
+ }
49
+
50
+ export function connectorStrokePx(width: number, dpr: number): number {
51
+ return _max(width, (1.5 / dpr))
52
+ }
@@ -0,0 +1,287 @@
1
+ // The `connector` mark shape: one instance is a stroked cubic between two
2
+ // placed points, `x` on the displayed region whose payload holds the instance
3
+ // and `x2` on the region `x2Region` names, each at the centre of its own row.
4
+ // Both place through a uniform table of the view's displayed regions, so a
5
+ // pan or zoom writes the table and no buffer. The curve is the breakpoint and
6
+ // read-pair connector both views draw: its handles leave each end along the
7
+ // read's direction on screen, flipped at a split junction's leading end, and
8
+ // the pair of controls lifts into a bow over a shared row or drops by `bend`
9
+ // px into a dip, the depth a caller sizes to the room it has.
10
+ //
11
+ // The hull is a triangle strip along the curve inflated by the half stroke and
12
+ // one antialiasing ramp, and the fragment fades on its distance across, which
13
+ // the strip's straight sections carry exactly. An instance can end in an open
14
+ // arrowhead, and a straight one can be dashed.
15
+ //! targets: wgsl, glsl
16
+ //! topology: triangle-strip
17
+ //! coverage: analytic
18
+ //! export-consts: CONNECTOR_CURVE_SEGMENTS, CONNECTOR_BOW, CONNECTOR_MAX_REACH_PX, CONNECTOR_APEX_RATIO, CONNECTOR_MAX_HANDLE_PX, CONNECTOR_MINUS_1, CONNECTOR_MINUS_2, CONNECTOR_LEADING_2, CONNECTOR_STRAIGHT, CONNECTOR_DASHED, CONNECTOR_ARROW
19
+ //! js-export: connectorBudgetPx, connectorHandlePx, connectorLiftPx, connectorTangent, connectorStrokePx
20
+
21
+ import antialias;
22
+ import colorPack;
23
+ import hpmath;
24
+ import viewRegion;
25
+
26
+ public static const uint CONNECTOR_CURVE_SEGMENTS = 48u;
27
+ static const uint CURVE_VERTS = (CONNECTOR_CURVE_SEGMENTS + 1u) * 2u;
28
+ // Each arrowhead arm's block of the strip: the join's repeated vertex, then its
29
+ // quad with the first corner doubled, so both joins are degenerate triangles.
30
+ static const uint ARM_VERTS = 6u;
31
+ public static const uint VERTS_PER_INSTANCE = CURVE_VERTS + 2u * ARM_VERTS;
32
+
33
+ // The `bend` lane's value for a connector that bows up over its row rather
34
+ // than dipping by a set depth.
35
+ public static const float CONNECTOR_BOW = -1.0e30;
36
+ // Every shaping term stays under this fraction of the span the curve covers,
37
+ // so a handle never folds the cubic back over itself.
38
+ static const float CONNECTOR_SPAN_FACTOR = 0.3;
39
+ public static const float CONNECTOR_MAX_HANDLE_PX = 200.0;
40
+ // The handles are horizontal, so a tall vertical gap only widens the bulge;
41
+ // past this it earns no more.
42
+ static const float CONNECTOR_MAX_VERTICAL_SPAN_PX = 150.0;
43
+ // A symmetric cubic's extreme sits 3/4 of the way from its ends to its
44
+ // controls, so a dip asked to reach a depth puts the controls 4/3 past it.
45
+ public static const float CONNECTOR_APEX_RATIO = 0.75;
46
+ static const float CONNECTOR_MAX_BOW_PX = 30.0;
47
+ // The deepest a dip may reach below its ends, a ceiling on `bend`.
48
+ public static const float CONNECTOR_MAX_REACH_PX = 110.0;
49
+
50
+ // The `bits` lane.
51
+ public static const uint CONNECTOR_MINUS_1 = 1u;
52
+ public static const uint CONNECTOR_MINUS_2 = 2u;
53
+ public static const uint CONNECTOR_LEADING_2 = 4u;
54
+ public static const uint CONNECTOR_STRAIGHT = 8u;
55
+ public static const uint CONNECTOR_DASHED = 16u;
56
+ public static const uint CONNECTOR_ARROW = 32u;
57
+
58
+ struct ConnectorInstance {
59
+ uint x : ATTR0;
60
+ uint x2 : ATTR1;
61
+ uint x2Region : ATTR2;
62
+ uint row : ATTR3;
63
+ uint row2 : ATTR4;
64
+ float bend : ATTR5;
65
+ float width : ATTR6;
66
+ uint color : ATTR7;
67
+ uint bits : ATTR8;
68
+ };
69
+
70
+ struct Uniforms {
71
+ float canvasHeight;
72
+ float canvasWidth;
73
+ float devicePixelRatio;
74
+ // Canvas y of row 0's centre, and the px between two rows' centres.
75
+ float rowOffsetPx;
76
+ float rowPitchPx;
77
+ float maxHandlePx;
78
+ float dashPx;
79
+ float gapPx;
80
+ float arrowPx;
81
+ uint regionCount;
82
+ float zero;
83
+ // The table entry of the region whose payload is drawing, which every
84
+ // instance's `x` is on.
85
+ float4 ownEntry;
86
+ float4 regionTable[VIEW_REGION_MAX];
87
+ };
88
+ [[vk::binding(1, 0)]] ConstantBuffer<Uniforms> u;
89
+
90
+ struct VsOut {
91
+ float4 position : SV_Position;
92
+ float4 color : COLOR0;
93
+ // Signed px from the centreline, and px along it from the `x` end.
94
+ float across : COLOR1;
95
+ float along : COLOR2;
96
+ nointerpolation float halfWidthPx : COLOR3;
97
+ nointerpolation float dashed : COLOR4;
98
+ };
99
+
100
+ // How much shaping a curve may spend: a share of the distance it covers.
101
+ public float connectorBudgetPx(float dx, float dy) {
102
+ float h = min(abs(dy), CONNECTOR_MAX_VERTICAL_SPAN_PX);
103
+ return sqrt(dx * dx + h * h) * CONNECTOR_SPAN_FACTOR;
104
+ }
105
+
106
+ public float connectorHandlePx(float budget, float maxHandlePx) {
107
+ return min(maxHandlePx, budget);
108
+ }
109
+
110
+ // How far both controls rise above their ends, negative for a dip. A bow fades
111
+ // as the rows separate, since a cross-row curve already has height; a dip is
112
+ // not held to the budget, because a vertical offset cannot fold the curve.
113
+ public float connectorLiftPx(float budget, float dy, float bend) {
114
+ return bend < -1.0e29
115
+ ? min(budget, max(0.0, CONNECTOR_MAX_BOW_PX - abs(dy)))
116
+ : -min(bend, CONNECTOR_MAX_REACH_PX) / CONNECTOR_APEX_RATIO;
117
+ }
118
+
119
+ // The screen sign of an end's handle: along the read's direction at a trailing
120
+ // end, against it at a split junction's leading end, mirrored on a reversed
121
+ // region.
122
+ public float connectorTangent(float strand, float leading, float reversed) {
123
+ return strand * (leading != 0.0 ? -1.0 : 1.0) * (reversed != 0.0 ? -1.0 : 1.0);
124
+ }
125
+
126
+ // Floored at 1.5 device px, so the single antialiasing ramp has room.
127
+ public float connectorStrokePx(float width, float dpr) {
128
+ return max(width, 1.5 / dpr);
129
+ }
130
+
131
+ struct Cubic {
132
+ float2 p0;
133
+ float2 p1;
134
+ float2 p2;
135
+ float2 p3;
136
+ };
137
+
138
+ float2 cubicAt(Cubic c, float t) {
139
+ float s = 1.0 - t;
140
+ return s * s * s * c.p0 + 3.0 * s * s * t * c.p1 + 3.0 * s * t * t * c.p2
141
+ + t * t * t * c.p3;
142
+ }
143
+
144
+ float2 cubicDirection(Cubic c, float t) {
145
+ float s = 1.0 - t;
146
+ float2 d = 3.0 * s * s * (c.p1 - c.p0) + 6.0 * s * t * (c.p2 - c.p1)
147
+ + 3.0 * t * t * (c.p3 - c.p2);
148
+ float len = length(d);
149
+ if (len > 1e-6) { return d / len; }
150
+ float2 chord = c.p3 - c.p0;
151
+ float chordLen = length(chord);
152
+ return chordLen > 1e-6 ? chord / chordLen : float2(1.0, 0.0);
153
+ }
154
+
155
+ float bitSet(uint bits, uint bit) {
156
+ return (bits & bit) != 0u ? 1.0 : 0.0;
157
+ }
158
+
159
+ Cubic placeCubic(ConnectorInstance inst, float4 entry2) {
160
+ Cubic c;
161
+ c.p0 = float2(viewRegionPx(inst.x, u.ownEntry, u.zero),
162
+ u.rowOffsetPx + float(inst.row) * u.rowPitchPx);
163
+ c.p3 = float2(viewRegionPx(inst.x2, entry2, u.zero),
164
+ u.rowOffsetPx + float(inst.row2) * u.rowPitchPx);
165
+ if ((inst.bits & CONNECTOR_STRAIGHT) != 0u) {
166
+ c.p1 = c.p0;
167
+ c.p2 = c.p3;
168
+ return c;
169
+ }
170
+ float2 d = c.p3 - c.p0;
171
+ float budget = connectorBudgetPx(d.x, d.y);
172
+ float handle = connectorHandlePx(budget, u.maxHandlePx);
173
+ float lift = connectorLiftPx(budget, d.y, inst.bend);
174
+ float t1 = connectorTangent(1.0 - 2.0 * bitSet(inst.bits, CONNECTOR_MINUS_1),
175
+ 0.0, u.ownEntry.w < 0.0 ? 1.0 : 0.0);
176
+ float t2 = connectorTangent(1.0 - 2.0 * bitSet(inst.bits, CONNECTOR_MINUS_2),
177
+ bitSet(inst.bits, CONNECTOR_LEADING_2),
178
+ entry2.w < 0.0 ? 1.0 : 0.0);
179
+ c.p1 = float2(c.p0.x + handle * t1, c.p0.y - lift);
180
+ c.p2 = float2(c.p3.x + handle * t2, c.p3.y - lift);
181
+ return c;
182
+ }
183
+
184
+ // The curve's length up to segment `seg`, as the strip's chords measure it.
185
+ float lengthTo(Cubic c, uint seg) {
186
+ float total = 0.0;
187
+ float2 prev = c.p0;
188
+ for (uint k = 1u; k <= seg; k++) {
189
+ float2 next = cubicAt(c, float(k) / float(CONNECTOR_CURVE_SEGMENTS));
190
+ total += length(next - prev);
191
+ prev = next;
192
+ }
193
+ return total;
194
+ }
195
+
196
+ struct StripVertex {
197
+ float2 screen;
198
+ float across;
199
+ float along;
200
+ };
201
+
202
+ StripVertex curveVertex(Cubic c, uint seg, float side, float hw, bool dashed) {
203
+ float t = float(seg) / float(CONNECTOR_CURVE_SEGMENTS);
204
+ float2 dir = cubicDirection(c, t);
205
+ StripVertex v;
206
+ v.across = side * hw;
207
+ v.screen = cubicAt(c, t) + float2(-dir.y, dir.x) * v.across;
208
+ v.along = dashed ? lengthTo(c, seg) : 0.0;
209
+ return v;
210
+ }
211
+
212
+ // An open arrowhead's arm `a` at the `x2` end, pointing the way the read
213
+ // continues: from the tip back and off the row by `arrowPx`.
214
+ float2 armEnd(Cubic c, uint a, float strand2, bool reversed2) {
215
+ float back = (reversed2 ? -strand2 : strand2) * -u.arrowPx;
216
+ return c.p3 + float2(back, a == 0u ? -u.arrowPx : u.arrowPx);
217
+ }
218
+
219
+ StripVertex armCorner(Cubic c, uint a, uint corner, float hw, float strand2, bool reversed2) {
220
+ float2 end = armEnd(c, a, strand2, reversed2);
221
+ float2 axis = end - c.p3;
222
+ float len = max(length(axis), 1e-6);
223
+ float2 dir = axis / len;
224
+ StripVertex v;
225
+ v.across = (corner % 2u == 0u) ? -hw : hw;
226
+ v.along = 0.0;
227
+ float at = corner >= 2u ? len : 0.0;
228
+ v.screen = c.p3 + dir * at + float2(-dir.y, dir.x) * v.across;
229
+ return v;
230
+ }
231
+
232
+ [shader("vertex")]
233
+ VsOut vs_main(ConnectorInstance inst, uint vid : SV_VertexID) {
234
+ bool placed = inst.x2Region < u.regionCount;
235
+ float4 entry2 = u.regionTable[min(inst.x2Region, VIEW_REGION_MAX - 1u)];
236
+ Cubic c = placeCubic(inst, entry2);
237
+ float halfWidth = 0.5 * connectorStrokePx(inst.width, u.devicePixelRatio);
238
+ float hw = halfWidth + aaHalfPx(u.devicePixelRatio);
239
+ bool dashed = (inst.bits & CONNECTOR_DASHED) != 0u;
240
+ bool arrow = (inst.bits & CONNECTOR_ARROW) != 0u;
241
+ float strand2 = 1.0 - 2.0 * bitSet(inst.bits, CONNECTOR_MINUS_2);
242
+ bool reversed2 = entry2.w < 0.0;
243
+
244
+ StripVertex v;
245
+ bool onArm = false;
246
+ if (vid < CURVE_VERTS) {
247
+ v = curveVertex(c, vid / 2u, (vid % 2u == 0u) ? -1.0 : 1.0, hw, dashed);
248
+ } else {
249
+ uint j = vid - CURVE_VERTS;
250
+ uint a = j / ARM_VERTS;
251
+ uint k = j % ARM_VERTS;
252
+ // The block starts from the vertex before it: the curve's last, or the
253
+ // first arm's last corner.
254
+ StripVertex start = a == 0u
255
+ ? curveVertex(c, CONNECTOR_CURVE_SEGMENTS, 1.0, hw, dashed)
256
+ : (arrow ? armCorner(c, 0u, 3u, hw, strand2, reversed2)
257
+ : curveVertex(c, CONNECTOR_CURVE_SEGMENTS, 1.0, hw, dashed));
258
+ if (k == 0u || !arrow) {
259
+ v = start;
260
+ } else {
261
+ v = armCorner(c, a, k <= 2u ? 0u : k - 2u, hw, strand2, reversed2);
262
+ onArm = true;
263
+ }
264
+ }
265
+
266
+ VsOut o;
267
+ o.position = placed
268
+ ? float4(v.screen.x / u.canvasWidth * 2.0 - 1.0,
269
+ yPxToClipY(v.screen.y, u.canvasHeight), 0.0, 1.0)
270
+ : float4(-2.0, -2.0, 0.0, 1.0);
271
+ o.color = unpackRGBA(inst.color);
272
+ o.across = v.across;
273
+ o.along = v.along;
274
+ o.halfWidthPx = halfWidth;
275
+ o.dashed = dashed && !onArm ? 1.0 : 0.0;
276
+ return o;
277
+ }
278
+
279
+ [shader("fragment")]
280
+ float4 fs_main(VsOut fragIn) : SV_Target {
281
+ float dash = fragIn.dashed > 0.5 && u.dashPx > 0.0
282
+ ? dashCoverage(fragIn.along, u.dashPx, u.gapPx, u.devicePixelRatio)
283
+ : 1.0;
284
+ float alpha = edgeCoverage(fragIn.halfWidthPx - abs(fragIn.across), u.devicePixelRatio)
285
+ * dash;
286
+ return float4(fragIn.color.rgb, fragIn.color.a * alpha);
287
+ }
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from connectorMark.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const WGSL_SOURCE = "struct Uniforms_std140_0\n{\n @align(16) canvasHeight_0 : f32,\n @align(4) canvasWidth_0 : f32,\n @align(8) devicePixelRatio_0 : f32,\n @align(4) rowOffsetPx_0 : f32,\n @align(16) rowPitchPx_0 : f32,\n @align(4) maxHandlePx_0 : f32,\n @align(8) dashPx_0 : f32,\n @align(4) gapPx_0 : f32,\n @align(16) arrowPx_0 : f32,\n @align(4) regionCount_0 : u32,\n @align(8) zero_0 : f32,\n @align(16) ownEntry_0 : vec4<f32>,\n @align(16) regionTable_0 : array<vec4<f32>, i32(256)>,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : Uniforms_std140_0;\nfn hpSplitUint_0( value_0 : u32) -> vec2<f32>\n{\n var lo_0 : u32 = (value_0 & (u32(4095)));\n return vec2<f32>(f32(value_0 - lo_0), f32(lo_0));\n}\n\nfn hpViewportOffsetBp_0( splitPos_0 : vec2<f32>, bpRange_0 : vec3<f32>, hpZero_0 : f32) -> f32\n{\n var floorBp_0 : f32 = -3.00000000549775576e+38f + hpZero_0;\n return max(bpRange_0.x - splitPos_0.x, floorBp_0) + max(bpRange_0.y - splitPos_0.y, floorBp_0);\n}\n\nfn viewRegionPx_0( bp_0 : u32, r_0 : vec4<f32>, hpZero_1 : f32) -> f32\n{\n return r_0.x - hpViewportOffsetBp_0(hpSplitUint_0(bp_0), vec3<f32>(r_0.y, r_0.z, 0.0f), hpZero_1) * r_0.w;\n}\n\nfn connectorBudgetPx_0( dx_0 : f32, dy_0 : f32) -> f32\n{\n var _S1 : f32 = min(abs(dy_0), 150.0f);\n return sqrt(dx_0 * dx_0 + _S1 * _S1) * 0.30000001192092896f;\n}\n\nfn connectorHandlePx_0( budget_0 : f32, maxHandlePx_1 : f32) -> f32\n{\n return min(maxHandlePx_1, budget_0);\n}\n\nfn connectorLiftPx_0( budget_1 : f32, dy_1 : f32, bend_0 : f32) -> f32\n{\n var _S2 : f32;\n if(bend_0 < -1.00000001504746622e+29f)\n {\n _S2 = min(budget_1, max(0.0f, 30.0f - abs(dy_1)));\n }\n else\n {\n _S2 = - min(bend_0, 110.0f) / 0.75f;\n }\n return _S2;\n}\n\nfn bitSet_0( bits_0 : u32, bit_0 : u32) -> f32\n{\n var _S3 : f32;\n if(((bits_0 & (bit_0))) != u32(0))\n {\n _S3 = 1.0f;\n }\n else\n {\n _S3 = 0.0f;\n }\n return _S3;\n}\n\nfn connectorTangent_0( strand_0 : f32, leading_0 : f32, reversed_0 : f32) -> f32\n{\n var _S4 : f32;\n if(leading_0 != 0.0f)\n {\n _S4 = -1.0f;\n }\n else\n {\n _S4 = 1.0f;\n }\n var _S5 : f32 = strand_0 * _S4;\n if(reversed_0 != 0.0f)\n {\n _S4 = -1.0f;\n }\n else\n {\n _S4 = 1.0f;\n }\n return _S5 * _S4;\n}\n\nstruct Cubic_0\n{\n p0_0 : vec2<f32>,\n p1_0 : vec2<f32>,\n p2_0 : vec2<f32>,\n p3_0 : vec2<f32>,\n};\n\nstruct ConnectorInstance_0\n{\n x_0 : u32,\n x2_0 : u32,\n x2Region_0 : u32,\n row_0 : u32,\n row2_0 : u32,\n bend_1 : f32,\n width_0 : f32,\n color_0 : u32,\n bits_1 : u32,\n};\n\nfn placeCubic_0( inst_0 : ConnectorInstance_0, entry2_0 : vec4<f32>) -> Cubic_0\n{\n var c_0 : Cubic_0;\n c_0.p0_0 = vec2<f32>(viewRegionPx_0(inst_0.x_0, u_0.ownEntry_0, u_0.zero_0), u_0.rowOffsetPx_0 + f32(inst_0.row_0) * u_0.rowPitchPx_0);\n c_0.p3_0 = vec2<f32>(viewRegionPx_0(inst_0.x2_0, entry2_0, u_0.zero_0), u_0.rowOffsetPx_0 + f32(inst_0.row2_0) * u_0.rowPitchPx_0);\n if((((inst_0.bits_1) & (u32(8)))) != u32(0))\n {\n c_0.p1_0 = c_0.p0_0;\n c_0.p2_0 = c_0.p3_0;\n return c_0;\n }\n var d_0 : vec2<f32> = c_0.p3_0 - c_0.p0_0;\n var _S6 : f32 = d_0.y;\n var budget_2 : f32 = connectorBudgetPx_0(d_0.x, _S6);\n var handle_0 : f32 = connectorHandlePx_0(budget_2, u_0.maxHandlePx_0);\n var lift_0 : f32 = connectorLiftPx_0(budget_2, _S6, inst_0.bend_1);\n var _S7 : f32 = 1.0f - 2.0f * bitSet_0(inst_0.bits_1, u32(1));\n var _S8 : f32;\n if((u_0.ownEntry_0.w) < 0.0f)\n {\n _S8 = 1.0f;\n }\n else\n {\n _S8 = 0.0f;\n }\n var t1_0 : f32 = connectorTangent_0(_S7, 0.0f, _S8);\n var _S9 : f32 = 1.0f - 2.0f * bitSet_0(inst_0.bits_1, u32(2));\n var _S10 : f32 = bitSet_0(inst_0.bits_1, u32(4));\n if((entry2_0.w) < 0.0f)\n {\n _S8 = 1.0f;\n }\n else\n {\n _S8 = 0.0f;\n }\n var t2_0 : f32 = connectorTangent_0(_S9, _S10, _S8);\n c_0.p1_0 = vec2<f32>(c_0.p0_0.x + handle_0 * t1_0, c_0.p0_0.y - lift_0);\n c_0.p2_0 = vec2<f32>(c_0.p3_0.x + handle_0 * t2_0, c_0.p3_0.y - lift_0);\n return c_0;\n}\n\nfn connectorStrokePx_0( width_1 : f32, dpr_0 : f32) -> f32\n{\n return max(width_1, 1.5f / dpr_0);\n}\n\nfn aaPx_0( dpr_1 : f32) -> f32\n{\n return 1.0f / max(dpr_1, 1.0f);\n}\n\nfn aaHalfPx_0( dpr_2 : f32) -> f32\n{\n return 0.5f * aaPx_0(dpr_2);\n}\n\nfn cubicDirection_0( c_1 : Cubic_0, t_0 : f32) -> vec2<f32>\n{\n var s_0 : f32 = 1.0f - t_0;\n var d_1 : vec2<f32> = vec2<f32>((3.0f * s_0 * s_0)) * (c_1.p1_0 - c_1.p0_0) + vec2<f32>((6.0f * s_0 * t_0)) * (c_1.p2_0 - c_1.p1_0) + vec2<f32>((3.0f * t_0 * t_0)) * (c_1.p3_0 - c_1.p2_0);\n var len_0 : f32 = length(d_1);\n if(len_0 > 9.99999997475242708e-07f)\n {\n return d_1 / vec2<f32>(len_0);\n }\n var chord_0 : vec2<f32> = c_1.p3_0 - c_1.p0_0;\n var chordLen_0 : f32 = length(chord_0);\n var _S11 : vec2<f32>;\n if(chordLen_0 > 9.99999997475242708e-07f)\n {\n _S11 = chord_0 / vec2<f32>(chordLen_0);\n }\n else\n {\n _S11 = vec2<f32>(1.0f, 0.0f);\n }\n return _S11;\n}\n\nfn cubicAt_0( c_2 : Cubic_0, t_1 : f32) -> vec2<f32>\n{\n var s_1 : f32 = 1.0f - t_1;\n var _S12 : f32 = 3.0f * s_1;\n return vec2<f32>((s_1 * s_1 * s_1)) * c_2.p0_0 + vec2<f32>((_S12 * s_1 * t_1)) * c_2.p1_0 + vec2<f32>((_S12 * t_1 * t_1)) * c_2.p2_0 + vec2<f32>((t_1 * t_1 * t_1)) * c_2.p3_0;\n}\n\nfn lengthTo_0( c_3 : Cubic_0, seg_0 : u32) -> f32\n{\n var prev_0 : vec2<f32> = c_3.p0_0;\n var k_0 : u32 = u32(1);\n var total_0 : f32 = 0.0f;\n for(;;)\n {\n if(k_0 <= seg_0)\n {\n }\n else\n {\n break;\n }\n var next_0 : vec2<f32> = cubicAt_0(c_3, f32(k_0) / 48.0f);\n var total_1 : f32 = total_0 + length(next_0 - prev_0);\n var _S13 : u32 = k_0 + u32(1);\n prev_0 = next_0;\n k_0 = _S13;\n total_0 = total_1;\n }\n return total_0;\n}\n\nstruct StripVertex_0\n{\n screen_0 : vec2<f32>,\n across_0 : f32,\n along_0 : f32,\n};\n\nfn curveVertex_0( c_4 : Cubic_0, seg_1 : u32, side_0 : f32, hw_0 : f32, dashed_0 : bool) -> StripVertex_0\n{\n var t_2 : f32 = f32(seg_1) / 48.0f;\n var dir_0 : vec2<f32> = cubicDirection_0(c_4, t_2);\n var v_0 : StripVertex_0;\n var _S14 : f32 = side_0 * hw_0;\n v_0.across_0 = _S14;\n v_0.screen_0 = cubicAt_0(c_4, t_2) + vec2<f32>(- dir_0.y, dir_0.x) * vec2<f32>(_S14);\n var _S15 : f32;\n if(dashed_0)\n {\n _S15 = lengthTo_0(c_4, seg_1);\n }\n else\n {\n _S15 = 0.0f;\n }\n v_0.along_0 = _S15;\n return v_0;\n}\n\nfn armEnd_0( c_5 : Cubic_0, a_0 : u32, strand2_0 : f32, reversed2_0 : bool) -> vec2<f32>\n{\n var _S16 : f32;\n if(reversed2_0)\n {\n _S16 = - strand2_0;\n }\n else\n {\n _S16 = strand2_0;\n }\n var back_0 : f32 = _S16 * - u_0.arrowPx_0;\n if(a_0 == u32(0))\n {\n _S16 = - u_0.arrowPx_0;\n }\n else\n {\n _S16 = u_0.arrowPx_0;\n }\n return c_5.p3_0 + vec2<f32>(back_0, _S16);\n}\n\nfn armCorner_0( c_6 : Cubic_0, a_1 : u32, corner_0 : u32, hw_1 : f32, strand2_1 : f32, reversed2_1 : bool) -> StripVertex_0\n{\n var axis_0 : vec2<f32> = armEnd_0(c_6, a_1, strand2_1, reversed2_1) - c_6.p3_0;\n var _S17 : f32 = max(length(axis_0), 9.99999997475242708e-07f);\n var dir_1 : vec2<f32> = axis_0 / vec2<f32>(_S17);\n var v_1 : StripVertex_0;\n var at_0 : f32;\n if((corner_0 % u32(2)) == u32(0))\n {\n at_0 = - hw_1;\n }\n else\n {\n at_0 = hw_1;\n }\n v_1.across_0 = at_0;\n v_1.along_0 = 0.0f;\n if(corner_0 >= u32(2))\n {\n at_0 = _S17;\n }\n else\n {\n at_0 = 0.0f;\n }\n v_1.screen_0 = c_6.p3_0 + dir_1 * vec2<f32>(at_0) + vec2<f32>(- dir_1.y, dir_1.x) * vec2<f32>(v_1.across_0);\n return v_1;\n}\n\nfn yPxToClipY_0( yPx_0 : f32, canvasHeight_1 : f32) -> f32\n{\n return 1.0f - yPx_0 / canvasHeight_1 * 2.0f;\n}\n\nfn unpackRGBA_0( c_7 : u32) -> vec4<f32>\n{\n return vec4<f32>(f32((((c_7 >> (u32(0)))) & (u32(255)))), f32((((c_7 >> (u32(8)))) & (u32(255)))), f32((((c_7 >> (u32(16)))) & (u32(255)))), f32((((c_7 >> (u32(24)))) & (u32(255))))) / vec4<f32>(255.0f);\n}\n\nstruct VsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_1 : vec4<f32>,\n @location(1) across_1 : f32,\n @location(2) along_1 : f32,\n @interpolate(flat) @location(3) halfWidthPx_0 : f32,\n @interpolate(flat) @location(4) dashed_1 : f32,\n};\n\nstruct vertexInput_0\n{\n @location(0) x_1 : u32,\n @location(1) x2_1 : u32,\n @location(2) x2Region_1 : u32,\n @location(3) row_1 : u32,\n @location(4) row2_1 : u32,\n @location(5) bend_2 : f32,\n @location(6) width_2 : f32,\n @location(7) color_2 : u32,\n @location(8) bits_2 : u32,\n};\n\n@vertex\nfn vs_main( _S18 : vertexInput_0, @builtin(vertex_index) vid_0 : u32) -> VsOut_0\n{\n var _S19 : ConnectorInstance_0 = ConnectorInstance_0( _S18.x_1, _S18.x2_1, _S18.x2Region_1, _S18.row_1, _S18.row2_1, _S18.bend_2, _S18.width_2, _S18.color_2, _S18.bits_2 );\n var placed_0 : bool = (_S18.x2Region_1) < (u_0.regionCount_0);\n var c_8 : Cubic_0 = placeCubic_0(_S19, u_0.regionTable_0[min(_S18.x2Region_1, u32(255))]);\n var halfWidth_0 : f32 = 0.5f * connectorStrokePx_0(_S18.width_2, u_0.devicePixelRatio_0);\n var hw_2 : f32 = halfWidth_0 + aaHalfPx_0(u_0.devicePixelRatio_0);\n var dashed_2 : bool = (((_S18.bits_2) & (u32(16)))) != u32(0);\n var arrow_0 : bool = (((_S18.bits_2) & (u32(32)))) != u32(0);\n var strand2_2 : f32 = 1.0f - 2.0f * bitSet_0(_S18.bits_2, u32(2));\n var reversed2_2 : bool = (u_0.regionTable_0[min(_S18.x2Region_1, u32(255))].w) < 0.0f;\n var v_2 : StripVertex_0;\n var onArm_0 : bool;\n var _S20 : f32;\n if(vid_0 < u32(98))\n {\n var _S21 : u32 = vid_0 / u32(2);\n if((vid_0 % u32(2)) == u32(0))\n {\n _S20 = -1.0f;\n }\n else\n {\n _S20 = 1.0f;\n }\n v_2 = curveVertex_0(c_8, _S21, _S20, hw_2, dashed_2);\n onArm_0 = false;\n }\n else\n {\n var j_0 : u32 = vid_0 - u32(98);\n var a_2 : u32 = j_0 / u32(6);\n var k_1 : u32 = j_0 % u32(6);\n var start_0 : StripVertex_0;\n if(a_2 == u32(0))\n {\n start_0 = curveVertex_0(c_8, u32(48), 1.0f, hw_2, dashed_2);\n }\n else\n {\n if(arrow_0)\n {\n start_0 = armCorner_0(c_8, u32(0), u32(3), hw_2, strand2_2, reversed2_2);\n }\n else\n {\n start_0 = curveVertex_0(c_8, u32(48), 1.0f, hw_2, dashed_2);\n }\n }\n if(k_1 == u32(0))\n {\n onArm_0 = true;\n }\n else\n {\n onArm_0 = !arrow_0;\n }\n if(onArm_0)\n {\n v_2 = start_0;\n onArm_0 = false;\n }\n else\n {\n var _S22 : u32;\n if(k_1 <= u32(2))\n {\n _S22 = u32(0);\n }\n else\n {\n _S22 = k_1 - u32(2);\n }\n v_2 = armCorner_0(c_8, a_2, _S22, hw_2, strand2_2, reversed2_2);\n onArm_0 = true;\n }\n }\n var o_0 : VsOut_0;\n var _S23 : vec4<f32>;\n if(placed_0)\n {\n _S23 = vec4<f32>(v_2.screen_0.x / u_0.canvasWidth_0 * 2.0f - 1.0f, yPxToClipY_0(v_2.screen_0.y, u_0.canvasHeight_0), 0.0f, 1.0f);\n }\n else\n {\n _S23 = vec4<f32>(-2.0f, -2.0f, 0.0f, 1.0f);\n }\n o_0.position_0 = _S23;\n o_0.color_1 = unpackRGBA_0(_S18.color_2);\n o_0.across_1 = v_2.across_0;\n o_0.along_1 = v_2.along_0;\n o_0.halfWidthPx_0 = halfWidth_0;\n if(dashed_2)\n {\n onArm_0 = !onArm_0;\n }\n else\n {\n onArm_0 = false;\n }\n if(onArm_0)\n {\n _S20 = 1.0f;\n }\n else\n {\n _S20 = 0.0f;\n }\n o_0.dashed_1 = _S20;\n return o_0;\n}\n\nfn aaRamp_0( signedInk_0 : f32, widthPx_0 : f32) -> f32\n{\n return clamp(signedInk_0 / widthPx_0 + 0.5f, 0.0f, 1.0f);\n}\n\nfn dashCoverageAt_0( coord_0 : f32, dashPx_1 : f32, gapPx_1 : f32, aaPx_1 : f32) -> f32\n{\n var period_0 : f32 = dashPx_1 + gapPx_1;\n var shifted_0 : f32 = coord_0 + gapPx_1 * 0.5f;\n return aaRamp_0(dashPx_1 * 0.5f - abs(shifted_0 - period_0 * floor(shifted_0 / period_0) - period_0 * 0.5f), aaPx_1);\n}\n\nfn dashCoverage_0( coord_1 : f32, dashPx_2 : f32, gapPx_2 : f32, dpr_3 : f32) -> f32\n{\n return dashCoverageAt_0(coord_1, dashPx_2, gapPx_2, aaPx_0(dpr_3));\n}\n\nfn edgeCoverage_0( signedInkCssPx_0 : f32, dpr_4 : f32) -> f32\n{\n return aaRamp_0(signedInkCssPx_0, aaPx_0(dpr_4));\n}\n\nstruct pixelOutput_0\n{\n @location(0) output_0 : vec4<f32>,\n};\n\nstruct pixelInput_0\n{\n @location(0) color_3 : vec4<f32>,\n @location(1) across_2 : f32,\n @location(2) along_2 : f32,\n @interpolate(flat) @location(3) halfWidthPx_1 : f32,\n @interpolate(flat) @location(4) dashed_3 : f32,\n};\n\n@fragment\nfn fs_main( _S24 : pixelInput_0, @builtin(position) position_1 : vec4<f32>) -> pixelOutput_0\n{\n var _S25 : bool;\n if((_S24.dashed_3) > 0.5f)\n {\n _S25 = (u_0.dashPx_0) > 0.0f;\n }\n else\n {\n _S25 = false;\n }\n var dash_0 : f32;\n if(_S25)\n {\n dash_0 = dashCoverage_0(_S24.along_2, u_0.dashPx_0, u_0.gapPx_0, u_0.devicePixelRatio_0);\n }\n else\n {\n dash_0 = 1.0f;\n }\n var _S26 : pixelOutput_0 = pixelOutput_0( vec4<f32>(_S24.color_3.xyz, _S24.color_3.w * (edgeCoverage_0(_S24.halfWidthPx_1 - abs(_S24.across_2), u_0.devicePixelRatio_0) * dash_0)) );\n return _S26;\n}\n\n"
@@ -95,16 +95,14 @@ public struct CoverageBandUniforms {
95
95
  };
96
96
 
97
97
  // Coverage-band clip indicator triangle, in CSS px: half-width and height.
98
- // Four consumers depend on this one number: coverageIndicator.slang draws the
99
- // triangle, coverageInterbase.slang hangs its bars directly below one, and the
100
- // Canvas2D painter + hit test read it from `@jbrowse/alignments-core` — which
101
- // the `consts-out` directive above generates from these declarations, so the
102
- // cross-package copy can't drift either.
98
+ // coverageInterbase.slang hangs its bars directly below one, and the point
99
+ // mark that draws it reads the size from `@jbrowse/alignments-core`, which the
100
+ // `consts-out` directive above generates from these declarations, so the
101
+ // cross-package copy can't drift.
103
102
  public static const float TRIANGLE_HW = 3.5;
104
103
  public static const float TRIANGLE_H = 4.5;
105
104
 
106
- // Shared vertex output for the band's four solid-fill passes. The indicator
107
- // pass carries a barycentric varying as well and declares its own.
105
+ // Shared vertex output for the band's solid-fill passes.
108
106
  public struct CoverageVsOut {
109
107
  public float4 position : SV_Position;
110
108
  public float4 color : COLOR0;
@@ -295,11 +293,11 @@ public float3 covSnpColor(float ct, CoverageBandUniforms u) {
295
293
  }
296
294
  }
297
295
 
298
- // Interbase mark fill, for both the histogram bars and the indicator triangles:
299
- // 1=insertion 2=softclip 3=hardclip, with anything else taking the insertion
300
- // color — the same fallback `drawIndicators`' lut takes for an out-of-range
301
- // kind. Nothing reaches that arm today (the interbase compute only ever emits
302
- // 1..3), which is exactly why the two spellings disagreeing would be invisible.
296
+ // The interbase histogram's fill: 1=insertion 2=softclip 3=hardclip, with
297
+ // anything else taking the insertion color — the same fallback
298
+ // `clipKindColor` takes for an out-of-range kind. Nothing reaches that arm
299
+ // today (the interbase compute only ever emits 1..3), which is exactly why the
300
+ // two spellings disagreeing would be invisible.
303
301
  public float3 covClipKindColor(float ct, CoverageBandUniforms u) {
304
302
  int ci = int(ct);
305
303
  if (ci == 2) { return unpackRGBA(u.colorSoftclipIndicator).xyz; }
@@ -1,6 +1,6 @@
1
1
  // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from coverageInterbase.slang.
2
2
  // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
3
 
4
- export const GLSL_VERTEX = "#version 300 es\nprecision highp float;\nprecision highp int;\nstruct CoverageBandUniforms_0\n{\n float bpHi_0;\n float bpLo_0;\n float bpLen_0;\n float hpZero_0;\n float canvasW_0;\n float canvasH_0;\n float covHeight_0;\n float covYOffset_0;\n float covTop_0;\n float regionMaxDepth_0;\n float depthDomainMax_0;\n float depthDomainMin_0;\n float coverageSymlogConstant_0;\n float binSize_0;\n float interbaseHeight_0;\n float snpMinFreq_0;\n float reversed_0;\n int coverageScaleType_0;\n uint colorCoverage_0;\n uint colorBaseA_0;\n uint colorBaseC_0;\n uint colorBaseG_0;\n uint colorBaseT_0;\n uint colorBaseN_0;\n uint colorInsertionIndicator_0;\n uint colorSoftclipIndicator_0;\n uint colorHardclipIndicator_0;\n};\n\n\nlayout(std140) uniform Uniforms\n{\n float bpHi_0;\n float bpLo_0;\n float bpLen_0;\n float hpZero_0;\n float canvasW_0;\n float canvasH_0;\n float covHeight_0;\n float covYOffset_0;\n float covTop_0;\n float regionMaxDepth_0;\n float depthDomainMax_0;\n float depthDomainMin_0;\n float coverageSymlogConstant_0;\n float binSize_0;\n float interbaseHeight_0;\n float snpMinFreq_0;\n float reversed_0;\n int coverageScaleType_0;\n uint colorCoverage_0;\n uint colorBaseA_0;\n uint colorBaseC_0;\n uint colorBaseG_0;\n uint colorBaseT_0;\n uint colorBaseN_0;\n uint colorInsertionIndicator_0;\n uint colorSoftclipIndicator_0;\n uint colorHardclipIndicator_0;\n}u_0;\n\nvec2 quadLocal_0(uint vid_0)\n{\n\n uint v_0 = vid_0 % 6U;\n\n bool _S1 = v_0 == 0U;\n\n bool _S2;\n\n if(_S1)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 2U;\n\n }\n\n if(_S2)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 3U;\n\n }\n\n float _S3;\n\n if(_S2)\n {\n\n _S3 = 0.0;\n\n }\n else\n {\n\n _S3 = 1.0;\n\n }\n if(_S1)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 1U;\n\n }\n\n if(_S2)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 4U;\n\n }\n\n float _S4;\n\n if(_S2)\n {\n\n _S4 = 0.0;\n\n }\n else\n {\n\n _S4 = 1.0;\n\n }\n\n return vec2(_S3, _S4);\n}\n\n\nvec2 hpSplitUint_0(uint value_0)\n{\n\n uint lo_0 = value_0 & 4095U;\n\n return vec2(float(value_0 - lo_0), float(lo_0));\n}\n\n\nfloat hpToClipX_0(vec2 splitPos_0, vec3 bpRange_0, float hpZero_1)\n{\n\n float floorBp_0 = -3.00000000549775576e+38 + hpZero_1;\n float step_0 = 2.0 / bpRange_0.z;\n\n\n return dot(vec3(-1.0, max(splitPos_0.x - bpRange_0.x, floorBp_0), max(splitPos_0.y - bpRange_0.y, floorBp_0)), vec3(1.0, step_0, step_0));\n}\n\n\nfloat covBpToClipX_0(uint bp_0, CoverageBandUniforms_0 u_1)\n{\n\n return hpToClipX_0(hpSplitUint_0(bp_0), vec3(u_1.bpHi_0, u_1.bpLo_0, u_1.bpLen_0), u_1.hpZero_0);\n}\n\n\nfloat pxToClipLen_0(float px_0, float size_0)\n{\n\n return px_0 * 2.0 / size_0;\n}\n\n\nfloat interbaseEdgePx_0(float offset_0, float interbaseHeight_1)\n{\n\n return floor(4.5 + offset_0 * interbaseHeight_1 + 0.5);\n}\n\n\nfloat yPxToClipY_0(float yPx_0, float canvasHeight_0)\n{\n\n return 1.0 - yPx_0 / canvasHeight_0 * 2.0;\n}\n\n\nfloat covAreaTop_0(CoverageBandUniforms_0 u_2)\n{\n\n return yPxToClipY_0(u_2.covTop_0, u_2.canvasH_0);\n}\n\n\nfloat covFlipX_0(float x_0, CoverageBandUniforms_0 u_3)\n{\n\n return mix(x_0, - x_0, u_3.reversed_0);\n}\n\n\nvec4 covFlippedQuad_0(float x0_0, float x1_0, float yBot_0, float yTop_0, vec2 local_0, CoverageBandUniforms_0 u_4)\n{\n return vec4(covFlipX_0(mix(x0_0, x1_0, local_0.x), u_4), mix(yBot_0, yTop_0, local_0.y), 0.0, 1.0);\n}\n\n\nvec4 unpackRGBA_0(uint c_0)\n{\n\n return vec4(float((c_0 >> 0U) & 255U), float((c_0 >> 8U) & 255U), float((c_0 >> 16U) & 255U), float((c_0 >> 24U) & 255U)) / 255.0;\n}\n\n\nvec3 covClipKindColor_0(float ct_0, CoverageBandUniforms_0 u_5)\n{\n\n int ci_0 = int(ct_0);\n if(ci_0 == 2)\n {\n\n return unpackRGBA_0(u_5.colorSoftclipIndicator_0).xyz;\n }\n\n if(ci_0 == 3)\n {\n\n return unpackRGBA_0(u_5.colorHardclipIndicator_0).xyz;\n }\n\n return unpackRGBA_0(u_5.colorInsertionIndicator_0).xyz;\n}\n\n\nout vec4 v_color;\n\n\nlayout(location = 0)\nin uint a_position;\n\n\nlayout(location = 1)\nin float a_yOffset;\n\n\nlayout(location = 2)\nin float a_segHeight;\n\n\nlayout(location = 3)\nin float a_colorType;\n\n\nstruct CoverageVsOut_0\n{\n vec4 position_0;\n vec4 color_0;\n};\n\n\nvoid main()\n{\n\n CoverageBandUniforms_0 _S5 = CoverageBandUniforms_0(u_0.bpHi_0, u_0.bpLo_0, u_0.bpLen_0, u_0.hpZero_0, u_0.canvasW_0, u_0.canvasH_0, u_0.covHeight_0, u_0.covYOffset_0, u_0.covTop_0, u_0.regionMaxDepth_0, u_0.depthDomainMax_0, u_0.depthDomainMin_0, u_0.coverageSymlogConstant_0, u_0.binSize_0, u_0.interbaseHeight_0, u_0.snpMinFreq_0, u_0.reversed_0, u_0.coverageScaleType_0, u_0.colorCoverage_0, u_0.colorBaseA_0, u_0.colorBaseC_0, u_0.colorBaseG_0, u_0.colorBaseT_0, u_0.colorBaseN_0, u_0.colorInsertionIndicator_0, u_0.colorSoftclipIndicator_0, u_0.colorHardclipIndicator_0);\n\n\n\n float cx_0 = covBpToClipX_0(a_position, _S5);\n\n float _S6 = covAreaTop_0(_S5);\n\n CoverageVsOut_0 o_0;\n\n float _S7 = pxToClipLen_0(1.0, u_0.canvasW_0) * 0.5;\n\n o_0.position_0 = covFlippedQuad_0(cx_0 - _S7, cx_0 + _S7, _S6 - pxToClipLen_0(interbaseEdgePx_0(a_yOffset + a_segHeight, u_0.interbaseHeight_0), u_0.canvasH_0), _S6 - pxToClipLen_0(interbaseEdgePx_0(a_yOffset, u_0.interbaseHeight_0), u_0.canvasH_0), quadLocal_0(uint(gl_VertexID)), _S5);\n o_0.color_0 = vec4(covClipKindColor_0(a_colorType, _S5), 1.0);\n CoverageVsOut_0 _S8 = o_0;\n\n gl_Position = o_0.position_0;\n\n v_color = _S8.color_0;\n\n return;\n}\n\n"
4
+ export const GLSL_VERTEX = "#version 300 es\nprecision highp float;\nprecision highp int;\nstruct CoverageBandUniforms_0\n{\n float bpHi_0;\n float bpLo_0;\n float bpLen_0;\n float hpZero_0;\n float canvasW_0;\n float canvasH_0;\n float covHeight_0;\n float covYOffset_0;\n float covTop_0;\n float regionMaxDepth_0;\n float depthDomainMax_0;\n float depthDomainMin_0;\n float coverageSymlogConstant_0;\n float binSize_0;\n float interbaseHeight_0;\n float snpMinFreq_0;\n float reversed_0;\n int coverageScaleType_0;\n uint colorCoverage_0;\n uint colorBaseA_0;\n uint colorBaseC_0;\n uint colorBaseG_0;\n uint colorBaseT_0;\n uint colorBaseN_0;\n uint colorInsertionIndicator_0;\n uint colorSoftclipIndicator_0;\n uint colorHardclipIndicator_0;\n};\n\n\nlayout(std140) uniform Uniforms\n{\n float bpHi_0;\n float bpLo_0;\n float bpLen_0;\n float hpZero_0;\n float canvasW_0;\n float canvasH_0;\n float covHeight_0;\n float covYOffset_0;\n float covTop_0;\n float regionMaxDepth_0;\n float depthDomainMax_0;\n float depthDomainMin_0;\n float coverageSymlogConstant_0;\n float binSize_0;\n float interbaseHeight_0;\n float snpMinFreq_0;\n float reversed_0;\n int coverageScaleType_0;\n uint colorCoverage_0;\n uint colorBaseA_0;\n uint colorBaseC_0;\n uint colorBaseG_0;\n uint colorBaseT_0;\n uint colorBaseN_0;\n uint colorInsertionIndicator_0;\n uint colorSoftclipIndicator_0;\n uint colorHardclipIndicator_0;\n}u_0;\n\nvec2 quadLocal_0(uint vid_0)\n{\n\n uint v_0 = vid_0 % 6U;\n\n bool _S1 = v_0 == 0U;\n\n bool _S2;\n\n if(_S1)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 2U;\n\n }\n\n if(_S2)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 3U;\n\n }\n\n float _S3;\n\n if(_S2)\n {\n\n _S3 = 0.0;\n\n }\n else\n {\n\n _S3 = 1.0;\n\n }\n if(_S1)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 1U;\n\n }\n\n if(_S2)\n {\n\n _S2 = true;\n\n }\n else\n {\n\n _S2 = v_0 == 4U;\n\n }\n\n float _S4;\n\n if(_S2)\n {\n\n _S4 = 0.0;\n\n }\n else\n {\n\n _S4 = 1.0;\n\n }\n\n return vec2(_S3, _S4);\n}\n\n\nvec2 hpSplitUint_0(uint value_0)\n{\n\n uint lo_0 = value_0 & 4095U;\n\n return vec2(float(value_0 - lo_0), float(lo_0));\n}\n\n\nfloat hpToClipX_0(vec2 splitPos_0, vec3 bpRange_0, float hpZero_1)\n{\n\n float floorBp_0 = -3.00000000549775576e+38 + hpZero_1;\n float step_0 = 2.0 / bpRange_0.z;\n\n\n return dot(vec3(-1.0, max(splitPos_0.x - bpRange_0.x, floorBp_0), max(splitPos_0.y - bpRange_0.y, floorBp_0)), vec3(1.0, step_0, step_0));\n}\n\n\nfloat covBpToClipX_0(uint bp_0, CoverageBandUniforms_0 u_1)\n{\n\n return hpToClipX_0(hpSplitUint_0(bp_0), vec3(u_1.bpHi_0, u_1.bpLo_0, u_1.bpLen_0), u_1.hpZero_0);\n}\n\nfloat covFlipX_0(float x_0, CoverageBandUniforms_0 u_2)\n{\n\n return mix(x_0, - x_0, u_2.reversed_0);\n}\n\n\nfloat clipXToPx_0(float clipX_0, float canvasWidth_0)\n{\n\n return (clipX_0 + 1.0) * 0.5 * canvasWidth_0;\n}\n\n\nfloat interbaseBarLeftPx_0(float centerPx_0)\n{\n\n return floor(centerPx_0);\n}\n\n\nfloat pxToClipX_0(float xPx_0, float canvasWidth_1)\n{\n\n return xPx_0 / canvasWidth_1 * 2.0 - 1.0;\n}\n\n\nfloat pxToClipLen_0(float px_0, float size_0)\n{\n\n return px_0 * 2.0 / size_0;\n}\n\n\nfloat interbaseEdgePx_0(float offset_0, float interbaseHeight_1)\n{\n\n return floor(4.5) + floor(offset_0 * interbaseHeight_1 + 0.5);\n}\n\n\nfloat yPxToClipY_0(float yPx_0, float canvasHeight_0)\n{\n\n return 1.0 - yPx_0 / canvasHeight_0 * 2.0;\n}\n\n\nfloat covAreaTop_0(CoverageBandUniforms_0 u_3)\n{\n\n return yPxToClipY_0(u_3.covTop_0, u_3.canvasH_0);\n}\n\n\nvec4 unpackRGBA_0(uint c_0)\n{\n\n return vec4(float((c_0 >> 0U) & 255U), float((c_0 >> 8U) & 255U), float((c_0 >> 16U) & 255U), float((c_0 >> 24U) & 255U)) / 255.0;\n}\n\n\nvec3 covClipKindColor_0(float ct_0, CoverageBandUniforms_0 u_4)\n{\n\n int ci_0 = int(ct_0);\n if(ci_0 == 2)\n {\n\n return unpackRGBA_0(u_4.colorSoftclipIndicator_0).xyz;\n }\n\n if(ci_0 == 3)\n {\n\n return unpackRGBA_0(u_4.colorHardclipIndicator_0).xyz;\n }\n\n return unpackRGBA_0(u_4.colorInsertionIndicator_0).xyz;\n}\n\n\nout vec4 v_color;\n\n\nlayout(location = 0)\nin uint a_position;\n\n\nlayout(location = 1)\nin float a_yOffset;\n\n\nlayout(location = 2)\nin float a_segHeight;\n\n\nlayout(location = 3)\nin float a_colorType;\n\n\nstruct CoverageVsOut_0\n{\n vec4 position_0;\n vec4 color_0;\n};\n\n\nvoid main()\n{\n vec2 local_0 = quadLocal_0(uint(gl_VertexID));\n\n CoverageBandUniforms_0 _S5 = CoverageBandUniforms_0(u_0.bpHi_0, u_0.bpLo_0, u_0.bpLen_0, u_0.hpZero_0, u_0.canvasW_0, u_0.canvasH_0, u_0.covHeight_0, u_0.covYOffset_0, u_0.covTop_0, u_0.regionMaxDepth_0, u_0.depthDomainMax_0, u_0.depthDomainMin_0, u_0.coverageSymlogConstant_0, u_0.binSize_0, u_0.interbaseHeight_0, u_0.snpMinFreq_0, u_0.reversed_0, u_0.coverageScaleType_0, u_0.colorCoverage_0, u_0.colorBaseA_0, u_0.colorBaseC_0, u_0.colorBaseG_0, u_0.colorBaseT_0, u_0.colorBaseN_0, u_0.colorInsertionIndicator_0, u_0.colorSoftclipIndicator_0, u_0.colorHardclipIndicator_0);\n\n\n float x0_0 = pxToClipX_0(interbaseBarLeftPx_0(clipXToPx_0(covFlipX_0(covBpToClipX_0(a_position, _S5), _S5), u_0.canvasW_0)), u_0.canvasW_0);\n\n float _S6 = covAreaTop_0(_S5);\n\n CoverageVsOut_0 o_0;\n\n o_0.position_0 = vec4(mix(x0_0, x0_0 + pxToClipLen_0(1.0, u_0.canvasW_0), local_0.x), mix(_S6 - pxToClipLen_0(interbaseEdgePx_0(a_yOffset + a_segHeight, u_0.interbaseHeight_0), u_0.canvasH_0), _S6 - pxToClipLen_0(interbaseEdgePx_0(a_yOffset, u_0.interbaseHeight_0), u_0.canvasH_0), local_0.y), 0.0, 1.0);\n o_0.color_0 = vec4(covClipKindColor_0(a_colorType, _S5), 1.0);\n CoverageVsOut_0 _S7 = o_0;\n\n gl_Position = o_0.position_0;\n\n v_color = _S7.color_0;\n\n return;\n}\n\n"
5
5
 
6
6
  export const GLSL_FRAGMENT = "#version 300 es\nprecision highp float;\nprecision highp int;\nlayout(location = 0)\nout vec4 entryPointParam_fs_main_0;\n\n\nin vec4 v_color;\n\n\nvoid main()\n{\n\n entryPointParam_fs_main_0 = v_color;\n\n return;\n}\n\n"
@@ -1,9 +1,9 @@
1
1
  // Interbase histogram: slim 1px-wide bars indicating insertion / softclip /
2
- // hardclip density across the coverage band, hanging from just below the
3
- // indicator triangles. See coverageBand.slang.
2
+ // hardclip density across the coverage band, hanging from the indicator
3
+ // triangles' tip row. See coverageBand.slang.
4
4
  //! targets: wgsl, glsl
5
5
  //! layout-out: packages/alignments-core/src/interbaseHistogramLayout.generated.ts
6
- //! js-export: interbaseEdgePx
6
+ //! js-export: interbaseEdgePx, interbaseBarLeftPx
7
7
  //! js-export-out: packages/alignments-core/src/interbaseEdge.generated.ts
8
8
 
9
9
  import coverageBand;
@@ -20,20 +20,24 @@ struct Instance {
20
20
  };
21
21
 
22
22
  // Screen-pixel Y of one edge of a bar, `offset` bars' worth of stacked height
23
- // below the coverage-area top.
23
+ // below the coverage-area top, snapped to a whole pixel. The backends disagree
24
+ // on a half-covered row: Canvas2D saturates the ~40 bars stacked in one column
25
+ // at 40bp/px to opaque, while this pass resolves their union once and stays at
26
+ // 50%. drawInterbaseSegments `//! js-export`s this so both sides round alike.
24
27
  //
25
- // Rounded to a whole pixel, and that rounding is the whole reason this is a
26
- // named function rather than two expressions inline. TRIANGLE_H is 4.5, so an
27
- // unsnapped edge half-covers a row — and the backends do not agree on a
28
- // half-covered row: Canvas2D composites each of the ~40 bars that stack in one
29
- // column at 40bp/px separately and saturates to opaque, while this pass resolves
30
- // the union coverage once and stays at 50%. That read as a full row of 128,0,128
31
- // against 191,127,191 and was the largest remaining cross-backend divergence.
32
- // Whole-pixel edges leave no partial coverage to disagree about — which only
33
- // holds while both sides round the same numbers the same way, so
34
- // drawInterbaseSegments `//! js-export`s this rather than repeating it.
28
+ // The bar starts on the row holding the triangle's tip, floor(TRIANGLE_H),
29
+ // rather than the row after it: the tip covers only a sliver of that row, so
30
+ // starting below it leaves a visible gap between triangle and bar.
35
31
  float interbaseEdgePx(float offset, float interbaseHeight) {
36
- return floor(TRIANGLE_H + offset * interbaseHeight + 0.5);
32
+ return floor(TRIANGLE_H) + floor(offset * interbaseHeight + 0.5);
33
+ }
34
+
35
+ // Left edge of the 1px bar centred on `centerPx`, snapped to the pixel column
36
+ // whose centre is nearest. Unsnapped, the bar straddles two columns: Canvas2D
37
+ // paints both at partial alpha while the GPU fills one solid, so the bar read
38
+ // paler than its triangle and the backends disagreed.
39
+ float interbaseBarLeftPx(float centerPx) {
40
+ return floor(centerPx);
37
41
  }
38
42
 
39
43
  [shader("vertex")]
@@ -41,18 +45,17 @@ CoverageVsOut vs_main(Instance inst, uint vid : SV_VertexID) {
41
45
  CoverageVsOut o;
42
46
  float2 local = quadLocal(vid);
43
47
 
44
- float cx = covBpToClipX(inst.position, u);
45
- float barW = pxToClipLen(1.0, u.canvasW);
48
+ float cx = covFlipX(covBpToClipX(inst.position, u), u);
49
+ float x0 = pxToClipX(interbaseBarLeftPx(clipXToPx(cx, u.canvasW)), u.canvasW);
50
+ float x1 = x0 + pxToClipLen(1.0, u.canvasW);
46
51
 
47
- // Hang from the coverage-area top, starting just below the indicator
48
- // triangle row (TRIANGLE_H is the same const coverageIndicator.slang draws
49
- // with). Both edges snap to whole pixels BEFORE the clip-space conversion.
52
+ // Both edges snap to whole pixels BEFORE the clip-space conversion.
50
53
  float topPx = interbaseEdgePx(inst.yOffset, u.interbaseHeight);
51
54
  float botPx = interbaseEdgePx(inst.yOffset + inst.segHeight, u.interbaseHeight);
52
55
  float sTop = covAreaTop(u) - pxToClipLen(topPx, u.canvasH);
53
56
  float sBot = covAreaTop(u) - pxToClipLen(botPx, u.canvasH);
54
57
 
55
- o.position = covFlippedQuad(cx - barW * 0.5, cx + barW * 0.5, sBot, sTop, local, u);
58
+ o.position = float4(lerp(x0, x1, local.x), lerp(sBot, sTop, local.y), 0.0, 1.0);
56
59
  o.color = float4(covClipKindColor(inst.colorType, u), 1.0);
57
60
  return o;
58
61
  }
@@ -1,4 +1,4 @@
1
1
  // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from coverageInterbase.slang.
2
2
  // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
3
 
4
- export const WGSL_SOURCE = "struct CoverageBandUniforms_std140_0\n{\n @align(16) bpHi_0 : f32,\n @align(4) bpLo_0 : f32,\n @align(8) bpLen_0 : f32,\n @align(4) hpZero_0 : f32,\n @align(16) canvasW_0 : f32,\n @align(4) canvasH_0 : f32,\n @align(8) covHeight_0 : f32,\n @align(4) covYOffset_0 : f32,\n @align(16) covTop_0 : f32,\n @align(4) regionMaxDepth_0 : f32,\n @align(8) depthDomainMax_0 : f32,\n @align(4) depthDomainMin_0 : f32,\n @align(16) coverageSymlogConstant_0 : f32,\n @align(4) binSize_0 : f32,\n @align(8) interbaseHeight_0 : f32,\n @align(4) snpMinFreq_0 : f32,\n @align(16) reversed_0 : f32,\n @align(4) coverageScaleType_0 : i32,\n @align(8) colorCoverage_0 : u32,\n @align(4) colorBaseA_0 : u32,\n @align(16) colorBaseC_0 : u32,\n @align(4) colorBaseG_0 : u32,\n @align(8) colorBaseT_0 : u32,\n @align(4) colorBaseN_0 : u32,\n @align(16) colorInsertionIndicator_0 : u32,\n @align(4) colorSoftclipIndicator_0 : u32,\n @align(8) colorHardclipIndicator_0 : u32,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : CoverageBandUniforms_std140_0;\nfn quadLocal_0( vid_0 : u32) -> vec2<f32>\n{\n var v_0 : u32 = vid_0 % u32(6);\n var _S1 : bool = v_0 == u32(0);\n var _S2 : bool;\n if(_S1)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(2);\n }\n if(_S2)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(3);\n }\n var _S3 : f32;\n if(_S2)\n {\n _S3 = 0.0f;\n }\n else\n {\n _S3 = 1.0f;\n }\n if(_S1)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(1);\n }\n if(_S2)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(4);\n }\n var _S4 : f32;\n if(_S2)\n {\n _S4 = 0.0f;\n }\n else\n {\n _S4 = 1.0f;\n }\n return vec2<f32>(_S3, _S4);\n}\n\nfn hpSplitUint_0( value_0 : u32) -> vec2<f32>\n{\n var lo_0 : u32 = (value_0 & (u32(4095)));\n return vec2<f32>(f32(value_0 - lo_0), f32(lo_0));\n}\n\nfn hpToClipX_0( splitPos_0 : vec2<f32>, bpRange_0 : vec3<f32>, hpZero_1 : f32) -> f32\n{\n var floorBp_0 : f32 = -3.00000000549775576e+38f + hpZero_1;\n var step_0 : f32 = 2.0f / bpRange_0.z;\n return dot(vec3<f32>(-1.0f, max(splitPos_0.x - bpRange_0.x, floorBp_0), max(splitPos_0.y - bpRange_0.y, floorBp_0)), vec3<f32>(1.0f, step_0, step_0));\n}\n\nfn covBpToClipX_0( bp_0 : u32, u_1 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return hpToClipX_0(hpSplitUint_0(bp_0), vec3<f32>((*u_1).bpHi_0, (*u_1).bpLo_0, (*u_1).bpLen_0), (*u_1).hpZero_0);\n}\n\nfn pxToClipLen_0( px_0 : f32, size_0 : f32) -> f32\n{\n return px_0 * 2.0f / size_0;\n}\n\nfn interbaseEdgePx_0( offset_0 : f32, interbaseHeight_1 : f32) -> f32\n{\n return floor(4.5f + offset_0 * interbaseHeight_1 + 0.5f);\n}\n\nfn yPxToClipY_0( yPx_0 : f32, canvasHeight_0 : f32) -> f32\n{\n return 1.0f - yPx_0 / canvasHeight_0 * 2.0f;\n}\n\nfn covAreaTop_0( u_2 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return yPxToClipY_0((*u_2).covTop_0, (*u_2).canvasH_0);\n}\n\nfn covFlipX_0( x_0 : f32, u_3 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return mix(x_0, - x_0, (*u_3).reversed_0);\n}\n\nfn covFlippedQuad_0( x0_0 : f32, x1_0 : f32, yBot_0 : f32, yTop_0 : f32, local_0 : vec2<f32>, u_4 : ptr<function, CoverageBandUniforms_std140_0>) -> vec4<f32>\n{\n var _S5 : f32 = covFlipX_0(mix(x0_0, x1_0, local_0.x), &((*u_4)));\n return vec4<f32>(_S5, mix(yBot_0, yTop_0, local_0.y), 0.0f, 1.0f);\n}\n\nfn unpackRGBA_0( c_0 : u32) -> vec4<f32>\n{\n return vec4<f32>(f32((((c_0 >> (u32(0)))) & (u32(255)))), f32((((c_0 >> (u32(8)))) & (u32(255)))), f32((((c_0 >> (u32(16)))) & (u32(255)))), f32((((c_0 >> (u32(24)))) & (u32(255))))) / vec4<f32>(255.0f);\n}\n\nfn covClipKindColor_0( ct_0 : f32, u_5 : ptr<function, CoverageBandUniforms_std140_0>) -> vec3<f32>\n{\n var ci_0 : i32 = i32(ct_0);\n if(ci_0 == i32(2))\n {\n return unpackRGBA_0((*u_5).colorSoftclipIndicator_0).xyz;\n }\n if(ci_0 == i32(3))\n {\n return unpackRGBA_0((*u_5).colorHardclipIndicator_0).xyz;\n }\n return unpackRGBA_0((*u_5).colorInsertionIndicator_0).xyz;\n}\n\nstruct CoverageVsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_0 : vec4<f32>,\n};\n\nstruct vertexInput_0\n{\n @location(0) position_1 : u32,\n @location(1) yOffset_0 : f32,\n @location(2) segHeight_0 : f32,\n @location(3) colorType_0 : f32,\n};\n\n@vertex\nfn vs_main( _S6 : vertexInput_0, @builtin(vertex_index) vid_1 : u32) -> CoverageVsOut_0\n{\n var local_1 : vec2<f32> = quadLocal_0(vid_1);\n var _S7 : CoverageBandUniforms_std140_0 = u_0;\n var _S8 : f32 = covBpToClipX_0(_S6.position_1, &(_S7));\n var barW_0 : f32 = pxToClipLen_0(1.0f, u_0.canvasW_0);\n var topPx_0 : f32 = interbaseEdgePx_0(_S6.yOffset_0, u_0.interbaseHeight_0);\n var botPx_0 : f32 = interbaseEdgePx_0(_S6.yOffset_0 + _S6.segHeight_0, u_0.interbaseHeight_0);\n var _S9 : f32 = covAreaTop_0(&(_S7));\n var o_0 : CoverageVsOut_0;\n var _S10 : f32 = barW_0 * 0.5f;\n var _S11 : vec4<f32> = covFlippedQuad_0(_S8 - _S10, _S8 + _S10, _S9 - pxToClipLen_0(botPx_0, u_0.canvasH_0), _S9 - pxToClipLen_0(topPx_0, u_0.canvasH_0), local_1, &(_S7));\n o_0.position_0 = _S11;\n var _S12 : vec3<f32> = covClipKindColor_0(_S6.colorType_0, &(_S7));\n o_0.color_0 = vec4<f32>(_S12, 1.0f);\n return o_0;\n}\n\nstruct pixelOutput_0\n{\n @location(0) output_0 : vec4<f32>,\n};\n\nstruct pixelInput_0\n{\n @location(0) color_1 : vec4<f32>,\n};\n\n@fragment\nfn fs_main( _S13 : pixelInput_0, @builtin(position) position_2 : vec4<f32>) -> pixelOutput_0\n{\n var _S14 : pixelOutput_0 = pixelOutput_0( _S13.color_1 );\n return _S14;\n}\n\n"
4
+ export const WGSL_SOURCE = "struct CoverageBandUniforms_std140_0\n{\n @align(16) bpHi_0 : f32,\n @align(4) bpLo_0 : f32,\n @align(8) bpLen_0 : f32,\n @align(4) hpZero_0 : f32,\n @align(16) canvasW_0 : f32,\n @align(4) canvasH_0 : f32,\n @align(8) covHeight_0 : f32,\n @align(4) covYOffset_0 : f32,\n @align(16) covTop_0 : f32,\n @align(4) regionMaxDepth_0 : f32,\n @align(8) depthDomainMax_0 : f32,\n @align(4) depthDomainMin_0 : f32,\n @align(16) coverageSymlogConstant_0 : f32,\n @align(4) binSize_0 : f32,\n @align(8) interbaseHeight_0 : f32,\n @align(4) snpMinFreq_0 : f32,\n @align(16) reversed_0 : f32,\n @align(4) coverageScaleType_0 : i32,\n @align(8) colorCoverage_0 : u32,\n @align(4) colorBaseA_0 : u32,\n @align(16) colorBaseC_0 : u32,\n @align(4) colorBaseG_0 : u32,\n @align(8) colorBaseT_0 : u32,\n @align(4) colorBaseN_0 : u32,\n @align(16) colorInsertionIndicator_0 : u32,\n @align(4) colorSoftclipIndicator_0 : u32,\n @align(8) colorHardclipIndicator_0 : u32,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : CoverageBandUniforms_std140_0;\nfn quadLocal_0( vid_0 : u32) -> vec2<f32>\n{\n var v_0 : u32 = vid_0 % u32(6);\n var _S1 : bool = v_0 == u32(0);\n var _S2 : bool;\n if(_S1)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(2);\n }\n if(_S2)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(3);\n }\n var _S3 : f32;\n if(_S2)\n {\n _S3 = 0.0f;\n }\n else\n {\n _S3 = 1.0f;\n }\n if(_S1)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(1);\n }\n if(_S2)\n {\n _S2 = true;\n }\n else\n {\n _S2 = v_0 == u32(4);\n }\n var _S4 : f32;\n if(_S2)\n {\n _S4 = 0.0f;\n }\n else\n {\n _S4 = 1.0f;\n }\n return vec2<f32>(_S3, _S4);\n}\n\nfn hpSplitUint_0( value_0 : u32) -> vec2<f32>\n{\n var lo_0 : u32 = (value_0 & (u32(4095)));\n return vec2<f32>(f32(value_0 - lo_0), f32(lo_0));\n}\n\nfn hpToClipX_0( splitPos_0 : vec2<f32>, bpRange_0 : vec3<f32>, hpZero_1 : f32) -> f32\n{\n var floorBp_0 : f32 = -3.00000000549775576e+38f + hpZero_1;\n var step_0 : f32 = 2.0f / bpRange_0.z;\n return dot(vec3<f32>(-1.0f, max(splitPos_0.x - bpRange_0.x, floorBp_0), max(splitPos_0.y - bpRange_0.y, floorBp_0)), vec3<f32>(1.0f, step_0, step_0));\n}\n\nfn covBpToClipX_0( bp_0 : u32, u_1 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return hpToClipX_0(hpSplitUint_0(bp_0), vec3<f32>((*u_1).bpHi_0, (*u_1).bpLo_0, (*u_1).bpLen_0), (*u_1).hpZero_0);\n}\n\nfn covFlipX_0( x_0 : f32, u_2 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return mix(x_0, - x_0, (*u_2).reversed_0);\n}\n\nfn clipXToPx_0( clipX_0 : f32, canvasWidth_0 : f32) -> f32\n{\n return (clipX_0 + 1.0f) * 0.5f * canvasWidth_0;\n}\n\nfn interbaseBarLeftPx_0( centerPx_0 : f32) -> f32\n{\n return floor(centerPx_0);\n}\n\nfn pxToClipX_0( xPx_0 : f32, canvasWidth_1 : f32) -> f32\n{\n return xPx_0 / canvasWidth_1 * 2.0f - 1.0f;\n}\n\nfn pxToClipLen_0( px_0 : f32, size_0 : f32) -> f32\n{\n return px_0 * 2.0f / size_0;\n}\n\nfn interbaseEdgePx_0( offset_0 : f32, interbaseHeight_1 : f32) -> f32\n{\n return floor(4.5f) + floor(offset_0 * interbaseHeight_1 + 0.5f);\n}\n\nfn yPxToClipY_0( yPx_0 : f32, canvasHeight_0 : f32) -> f32\n{\n return 1.0f - yPx_0 / canvasHeight_0 * 2.0f;\n}\n\nfn covAreaTop_0( u_3 : ptr<function, CoverageBandUniforms_std140_0>) -> f32\n{\n return yPxToClipY_0((*u_3).covTop_0, (*u_3).canvasH_0);\n}\n\nfn unpackRGBA_0( c_0 : u32) -> vec4<f32>\n{\n return vec4<f32>(f32((((c_0 >> (u32(0)))) & (u32(255)))), f32((((c_0 >> (u32(8)))) & (u32(255)))), f32((((c_0 >> (u32(16)))) & (u32(255)))), f32((((c_0 >> (u32(24)))) & (u32(255))))) / vec4<f32>(255.0f);\n}\n\nfn covClipKindColor_0( ct_0 : f32, u_4 : ptr<function, CoverageBandUniforms_std140_0>) -> vec3<f32>\n{\n var ci_0 : i32 = i32(ct_0);\n if(ci_0 == i32(2))\n {\n return unpackRGBA_0((*u_4).colorSoftclipIndicator_0).xyz;\n }\n if(ci_0 == i32(3))\n {\n return unpackRGBA_0((*u_4).colorHardclipIndicator_0).xyz;\n }\n return unpackRGBA_0((*u_4).colorInsertionIndicator_0).xyz;\n}\n\nstruct CoverageVsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_0 : vec4<f32>,\n};\n\nstruct vertexInput_0\n{\n @location(0) position_1 : u32,\n @location(1) yOffset_0 : f32,\n @location(2) segHeight_0 : f32,\n @location(3) colorType_0 : f32,\n};\n\n@vertex\nfn vs_main( _S5 : vertexInput_0, @builtin(vertex_index) vid_1 : u32) -> CoverageVsOut_0\n{\n var local_0 : vec2<f32> = quadLocal_0(vid_1);\n var _S6 : CoverageBandUniforms_std140_0 = u_0;\n var _S7 : f32 = covBpToClipX_0(_S5.position_1, &(_S6));\n var _S8 : f32 = covFlipX_0(_S7, &(_S6));\n var x0_0 : f32 = pxToClipX_0(interbaseBarLeftPx_0(clipXToPx_0(_S8, u_0.canvasW_0)), u_0.canvasW_0);\n var x1_0 : f32 = x0_0 + pxToClipLen_0(1.0f, u_0.canvasW_0);\n var topPx_0 : f32 = interbaseEdgePx_0(_S5.yOffset_0, u_0.interbaseHeight_0);\n var botPx_0 : f32 = interbaseEdgePx_0(_S5.yOffset_0 + _S5.segHeight_0, u_0.interbaseHeight_0);\n var _S9 : f32 = covAreaTop_0(&(_S6));\n var o_0 : CoverageVsOut_0;\n o_0.position_0 = vec4<f32>(mix(x0_0, x1_0, local_0.x), mix(_S9 - pxToClipLen_0(botPx_0, u_0.canvasH_0), _S9 - pxToClipLen_0(topPx_0, u_0.canvasH_0), local_0.y), 0.0f, 1.0f);\n var _S10 : vec3<f32> = covClipKindColor_0(_S5.colorType_0, &(_S6));\n o_0.color_0 = vec4<f32>(_S10, 1.0f);\n return o_0;\n}\n\nstruct pixelOutput_0\n{\n @location(0) output_0 : vec4<f32>,\n};\n\nstruct pixelInput_0\n{\n @location(0) color_1 : vec4<f32>,\n};\n\n@fragment\nfn fs_main( _S11 : pixelInput_0, @builtin(position) position_2 : vec4<f32>) -> pixelOutput_0\n{\n var _S12 : pixelOutput_0 = pixelOutput_0( _S11.color_1 );\n return _S12;\n}\n\n"
@@ -15,7 +15,7 @@ public static const uint VERTS_PER_INSTANCE = 6u;
15
15
  // via covNormalizeDepth, so each segment is a linear slice of a possibly
16
16
  // log-scaled bar without any per-position un-mixing at draw time.
17
17
  //
18
- // Which means that on a LOG axis the coloured fraction reads as the allele
18
+ // Which means that on a LOG axis the colored fraction reads as the allele
19
19
  // proportion and not as a count off the y-axis: a 50% allele is half the bar
20
20
  // whatever the scale, so its top edge does not land on the depth the axis would
21
21
  // read there. Deliberate — the alternative bakes the axis into the buffer and