@jbrowse/render-core 5.0.0-beta.7 → 5.0.0-beta.9

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 (174) hide show
  1. package/esm/RenderCanvas.d.ts +2 -2
  2. package/esm/RenderLifecycleMixin.d.ts +7 -6
  3. package/esm/RenderLifecycleMixin.js +7 -6
  4. package/esm/canvas2dUtils.d.ts +58 -17
  5. package/esm/canvas2dUtils.js +82 -30
  6. package/esm/computePipeline.d.ts +4 -3
  7. package/esm/computePipeline.js +21 -14
  8. package/esm/coverageBand.d.ts +3 -3
  9. package/esm/coverageBand.js +2 -2
  10. package/esm/coverageBandBuffers.d.ts +2 -3
  11. package/esm/createRenderingBackend.d.ts +1 -1
  12. package/esm/displayPhase.d.ts +79 -109
  13. package/esm/displayPhase.js +42 -83
  14. package/esm/gpuDevice.d.ts +11 -10
  15. package/esm/gpuDevice.js +10 -11
  16. package/esm/graphicsCapabilities.d.ts +6 -7
  17. package/esm/graphicsCapabilities.js +3 -4
  18. package/esm/hal/createHal.js +1 -1
  19. package/esm/hal/deviceGpuCache.d.ts +25 -30
  20. package/esm/hal/deviceGpuCache.js +85 -97
  21. package/esm/hal/index.d.ts +2 -2
  22. package/esm/hal/index.js +1 -1
  23. package/esm/hal/mockHal.d.ts +8 -6
  24. package/esm/hal/mockHal.js +7 -2
  25. package/esm/hal/passIds.d.ts +8 -7
  26. package/esm/hal/passIds.js +11 -10
  27. package/esm/hal/types.d.ts +28 -12
  28. package/esm/hal/webgl2Hal.d.ts +11 -3
  29. package/esm/hal/webgl2Hal.js +116 -145
  30. package/esm/hal/webgpuHal.d.ts +8 -8
  31. package/esm/hal/webgpuHal.js +97 -124
  32. package/esm/instancePass.d.ts +2 -1
  33. package/esm/mapUploadSync.d.ts +2 -2
  34. package/esm/mapUploadSync.js +2 -2
  35. package/esm/marks/barMark.d.ts +6 -3
  36. package/esm/marks/barMark.js +19 -13
  37. package/esm/marks/drawAgainstHit.d.ts +58 -39
  38. package/esm/marks/drawAgainstHit.js +136 -96
  39. package/esm/marks/glyphPaint.d.ts +14 -2
  40. package/esm/marks/glyphPaint.js +16 -2
  41. package/esm/marks/index.d.ts +4 -2
  42. package/esm/marks/index.js +3 -2
  43. package/esm/marks/markBackend.d.ts +2 -2
  44. package/esm/marks/markBackend.js +2 -2
  45. package/esm/marks/markHit.d.ts +2 -2
  46. package/esm/marks/markHit.js +2 -2
  47. package/esm/marks/markPlan.d.ts +2 -2
  48. package/esm/marks/markPlan.js +2 -2
  49. package/esm/marks/markRamp.d.ts +1 -3
  50. package/esm/marks/markRamp.js +1 -5
  51. package/esm/marks/nearestMarkHit.d.ts +49 -0
  52. package/esm/marks/nearestMarkHit.js +126 -0
  53. package/esm/marks/pointMark.d.ts +9 -2
  54. package/esm/marks/pointMark.js +36 -31
  55. package/esm/marks/rowLane.d.ts +17 -0
  56. package/esm/marks/rowLane.js +11 -0
  57. package/esm/marks/spanMark.d.ts +6 -26
  58. package/esm/marks/spanMark.js +34 -31
  59. package/esm/marks/types.d.ts +51 -181
  60. package/esm/marks/types.js +91 -131
  61. package/esm/namedReactions.d.ts +3 -4
  62. package/esm/namedReactions.js +3 -4
  63. package/esm/scoreScale.d.ts +20 -0
  64. package/esm/scoreScale.js +77 -0
  65. package/esm/shaders/barMark.generated.d.ts +2 -3
  66. package/esm/shaders/barMark.generated.js +4 -3
  67. package/esm/shaders/barMark.glsl.generated.d.ts +2 -0
  68. package/esm/shaders/barMark.glsl.generated.js +4 -0
  69. package/esm/shaders/barMark.iface.generated.d.ts +12 -6
  70. package/esm/shaders/barMark.iface.generated.js +27 -15
  71. package/esm/shaders/barMark.wgsl.generated.d.ts +1 -0
  72. package/esm/shaders/barMark.wgsl.generated.js +3 -0
  73. package/esm/shaders/coverageBar.generated.d.ts +2 -3
  74. package/esm/shaders/coverageBar.generated.js +4 -3
  75. package/esm/shaders/coverageBar.glsl.generated.d.ts +2 -0
  76. package/esm/shaders/coverageBar.glsl.generated.js +4 -0
  77. package/esm/shaders/coverageBar.iface.generated.js +1 -1
  78. package/esm/shaders/coverageBar.wgsl.generated.d.ts +1 -0
  79. package/esm/shaders/coverageBar.wgsl.generated.js +3 -0
  80. package/esm/shaders/coverageIndicator.generated.d.ts +2 -3
  81. package/esm/shaders/coverageIndicator.generated.js +4 -3
  82. package/esm/shaders/coverageIndicator.glsl.generated.d.ts +2 -0
  83. package/esm/shaders/coverageIndicator.glsl.generated.js +4 -0
  84. package/esm/shaders/coverageIndicator.iface.generated.js +1 -1
  85. package/esm/shaders/coverageIndicator.wgsl.generated.d.ts +1 -0
  86. package/esm/shaders/coverageIndicator.wgsl.generated.js +3 -0
  87. package/esm/shaders/coverageInterbase.generated.d.ts +2 -3
  88. package/esm/shaders/coverageInterbase.generated.js +4 -3
  89. package/esm/shaders/coverageInterbase.glsl.generated.d.ts +2 -0
  90. package/esm/shaders/coverageInterbase.glsl.generated.js +4 -0
  91. package/esm/shaders/coverageInterbase.iface.generated.js +1 -1
  92. package/esm/shaders/coverageInterbase.wgsl.generated.d.ts +1 -0
  93. package/esm/shaders/coverageInterbase.wgsl.generated.js +3 -0
  94. package/esm/shaders/coverageMod.generated.d.ts +2 -3
  95. package/esm/shaders/coverageMod.generated.js +4 -3
  96. package/esm/shaders/coverageMod.glsl.generated.d.ts +2 -0
  97. package/esm/shaders/coverageMod.glsl.generated.js +4 -0
  98. package/esm/shaders/coverageMod.iface.generated.js +1 -1
  99. package/esm/shaders/coverageMod.wgsl.generated.d.ts +1 -0
  100. package/esm/shaders/coverageMod.wgsl.generated.js +3 -0
  101. package/esm/shaders/coverageSnp.generated.d.ts +2 -3
  102. package/esm/shaders/coverageSnp.generated.js +4 -3
  103. package/esm/shaders/coverageSnp.glsl.generated.d.ts +2 -0
  104. package/esm/shaders/coverageSnp.glsl.generated.js +4 -0
  105. package/esm/shaders/coverageSnp.iface.generated.js +1 -1
  106. package/esm/shaders/coverageSnp.wgsl.generated.d.ts +1 -0
  107. package/esm/shaders/coverageSnp.wgsl.generated.js +3 -0
  108. package/esm/shaders/pointMark.generated.d.ts +2 -3
  109. package/esm/shaders/pointMark.generated.js +4 -3
  110. package/esm/shaders/pointMark.glsl.generated.d.ts +2 -0
  111. package/esm/shaders/pointMark.glsl.generated.js +4 -0
  112. package/esm/shaders/pointMark.iface.generated.d.ts +11 -3
  113. package/esm/shaders/pointMark.iface.generated.js +23 -9
  114. package/esm/shaders/pointMark.js.generated.d.ts +1 -1
  115. package/esm/shaders/pointMark.js.generated.js +51 -29
  116. package/esm/shaders/pointMark.wgsl.generated.d.ts +1 -0
  117. package/esm/shaders/pointMark.wgsl.generated.js +3 -0
  118. package/esm/shaders/scoreScale.js.generated.js +46 -22
  119. package/esm/shaders/spanMark.generated.d.ts +2 -3
  120. package/esm/shaders/spanMark.generated.js +4 -3
  121. package/esm/shaders/spanMark.glsl.generated.d.ts +2 -0
  122. package/esm/shaders/spanMark.glsl.generated.js +4 -0
  123. package/esm/shaders/spanMark.iface.generated.js +1 -1
  124. package/esm/shaders/spanMark.wgsl.generated.d.ts +1 -0
  125. package/esm/shaders/spanMark.wgsl.generated.js +3 -0
  126. package/esm/slangPass.d.ts +9 -10
  127. package/esm/slangPass.js +9 -3
  128. package/esm/useGraphicsCapabilities.d.ts +1 -1
  129. package/esm/useGraphicsCapabilities.js +1 -1
  130. package/esm/webgpuUtils.d.ts +3 -11
  131. package/esm/webgpuUtils.js +12 -33
  132. package/package.json +3 -2
  133. package/src/shaders/barMark.generated.ts +6 -5
  134. package/src/shaders/barMark.glsl.generated.ts +6 -0
  135. package/src/shaders/barMark.iface.generated.ts +31 -15
  136. package/src/shaders/barMark.slang +11 -3
  137. package/src/shaders/barMark.wgsl.generated.ts +4 -0
  138. package/src/shaders/colorPack.slang +3 -2
  139. package/src/shaders/coverageBand.slang +5 -11
  140. package/src/shaders/coverageBar.generated.ts +6 -5
  141. package/src/shaders/coverageBar.glsl.generated.ts +6 -0
  142. package/src/shaders/coverageBar.iface.generated.ts +1 -1
  143. package/src/shaders/coverageBar.slang +1 -1
  144. package/src/shaders/coverageBar.wgsl.generated.ts +4 -0
  145. package/src/shaders/coverageIndicator.generated.ts +6 -5
  146. package/src/shaders/coverageIndicator.glsl.generated.ts +6 -0
  147. package/src/shaders/coverageIndicator.iface.generated.ts +1 -1
  148. package/src/shaders/coverageIndicator.wgsl.generated.ts +4 -0
  149. package/src/shaders/coverageInterbase.generated.ts +6 -5
  150. package/src/shaders/coverageInterbase.glsl.generated.ts +6 -0
  151. package/src/shaders/coverageInterbase.iface.generated.ts +1 -1
  152. package/src/shaders/coverageInterbase.wgsl.generated.ts +4 -0
  153. package/src/shaders/coverageMod.generated.ts +6 -5
  154. package/src/shaders/coverageMod.glsl.generated.ts +6 -0
  155. package/src/shaders/coverageMod.iface.generated.ts +1 -1
  156. package/src/shaders/coverageMod.wgsl.generated.ts +4 -0
  157. package/src/shaders/coverageSnp.generated.ts +6 -5
  158. package/src/shaders/coverageSnp.glsl.generated.ts +6 -0
  159. package/src/shaders/coverageSnp.iface.generated.ts +1 -1
  160. package/src/shaders/coverageSnp.wgsl.generated.ts +4 -0
  161. package/src/shaders/hpmath.slang +18 -6
  162. package/src/shaders/pointMark.generated.ts +6 -6
  163. package/src/shaders/pointMark.glsl.generated.ts +6 -0
  164. package/src/shaders/pointMark.iface.generated.ts +28 -9
  165. package/src/shaders/pointMark.js.generated.ts +48 -29
  166. package/src/shaders/pointMark.slang +18 -5
  167. package/src/shaders/pointMark.wgsl.generated.ts +4 -0
  168. package/src/shaders/scoreScale.js.generated.ts +43 -22
  169. package/src/shaders/scoreScale.slang +37 -53
  170. package/src/shaders/spanMark.generated.ts +6 -5
  171. package/src/shaders/spanMark.glsl.generated.ts +6 -0
  172. package/src/shaders/spanMark.iface.generated.ts +1 -1
  173. package/src/shaders/spanMark.wgsl.generated.ts +4 -0
  174. package/src/shaders/valueScale.slang +8 -45
@@ -16,49 +16,68 @@ function _min(a: number, b: number) {
16
16
  return b < a || Number.isNaN(a) ? b : a
17
17
  }
18
18
 
19
+ function log1pf(x: number): number {
20
+ let u = (1.0 + x)
21
+ let _t0: number
22
+ if ((u == 1.0)) {
23
+ _t0 = x
24
+ } else {
25
+ _t0 = (Math.log(u) * (x / (u - 1.0)))
26
+ }
27
+ return _t0
28
+ }
29
+
19
30
  function symlogTransform(x: number, c: number): number {
20
- return ((((Math.sign(x)) | 0)) * Math.log((1.0 + Math.abs((x / c)))))
31
+ return ((((Math.sign(x)) | 0)) * log1pf(Math.abs((x / c))))
21
32
  }
22
33
 
23
34
  function normalizeScore(score: number, domainMin: number, domainMax: number, scaleType: number, symlogConstant: number): number {
35
+ let tMax: number
36
+ let tMin: number
37
+ let t: number
24
38
  if ((scaleType == 2)) {
25
- let tMin = symlogTransform(domainMin, symlogConstant)
26
- let tRange = (symlogTransform(domainMax, symlogConstant) - tMin)
27
- if ((tRange <= 0.0)) {
28
- return 0.0
39
+ let _t0 = symlogTransform(score, symlogConstant)
40
+ let _t1 = symlogTransform(domainMin, symlogConstant)
41
+ tMax = symlogTransform(domainMax, symlogConstant)
42
+ tMin = _t1
43
+ t = _t0
44
+ } else {
45
+ if ((scaleType == 1)) {
46
+ if ((domainMin > 0.0)) {
47
+ tMax = domainMin
48
+ } else {
49
+ tMax = 1.0
50
+ }
51
+ let _t2 = Math.log2(_max(score, tMax))
52
+ let _t3 = Math.log2(tMax)
53
+ tMax = Math.log2(_max(domainMax, tMax))
54
+ tMin = _t3
55
+ t = _t2
56
+ } else {
57
+ tMax = domainMax
58
+ tMin = domainMin
59
+ t = score
29
60
  }
30
- return _clamp(((symlogTransform(score, symlogConstant) - tMin) / tRange), 0.0, 1.0)
31
61
  }
32
- if ((scaleType == 1)) {
33
- let floorV: number
34
- if ((domainMin > 0.0)) {
35
- floorV = domainMin
62
+ let tRange = (tMax - tMin)
63
+ if ((tRange <= 0.0)) {
64
+ if ((t > tMin)) {
65
+ tMax = 1.0
36
66
  } else {
37
- floorV = 1.0
38
- }
39
- let logMin = Math.log2(floorV)
40
- let logRange = (Math.log2(_max(domainMax, floorV)) - logMin)
41
- if ((logRange <= 0.0)) {
42
- return 0.0
67
+ tMax = 0.0
43
68
  }
44
- return _clamp(((Math.log2(_max(score, floorV)) - logMin) / logRange), 0.0, 1.0)
69
+ return tMax
45
70
  }
46
- let range = (domainMax - domainMin)
47
- if ((range <= 0.0)) {
48
- return 0.0
49
- }
50
- return _clamp(((score - domainMin) / range), 0.0, 1.0)
71
+ return _clamp(((t - tMin) / tRange), 0.0, 1.0)
51
72
  }
52
73
 
53
- export function valueToYPx(value: number, domainMin: number, domainMax: number, h: number): number {
54
- return ((1.0 - _clamp(((value - domainMin) / _max((domainMax - domainMin), 9.99999997475242708e-07)), 0.0, 1.0)) * h)
74
+ export function valueToYPxScaled(value: number, domainMin: number, domainMax: number, h: number, scaleType: number): number {
75
+ return ((1.0 - normalizeScore(value, domainMin, domainMax, scaleType, 1.0)) * h)
55
76
  }
56
77
 
57
- export function valueToYPxScaled(value: number, domainMin: number, domainMax: number, h: number, scaleType: number): number {
58
- if ((scaleType == 1)) {
59
- return ((1.0 - normalizeScore(value, domainMin, domainMax, 1, 1.0)) * h)
60
- }
61
- return valueToYPx(value, domainMin, domainMax, h)
78
+ export function pointYPx(value: number, domainMin: number, domainMax: number, h: number, scaleType: number, insetPx: number): number {
79
+ let _t0 = _min(insetPx, (h * 0.5))
80
+ return (_t0 + valueToYPxScaled(value, domainMin, domainMax, (h - (2.0 * _t0)), scaleType))
62
81
  }
63
82
 
64
83
  export function pointDrawsBar(spanPx: number, radiusPx: number): boolean {
@@ -1,5 +1,5 @@
1
1
  // The `point` mark shape: one glyph per instance, placed at a genomic x and at
2
- // a y read off a per-instance value through a linear domain scale. The glyph
2
+ // a y read off a per-instance value through `valueScale`. The glyph
3
3
  // channel picks between a disc, an inverted triangle and a diamond, and an
4
4
  // instance whose x..x2 extent is wider than the glyph draws as a horizontal bar
5
5
  // instead — the shape's own answer to "this datum has extent".
@@ -7,9 +7,8 @@
7
7
  // All four are a 6-vertex quad; the fragment shader carves the shape.
8
8
  //! targets: wgsl, glsl
9
9
  //! export-consts: DIAMOND_GLYPH_SCALE, GLYPH_DISC, GLYPH_TRIANGLE, GLYPH_DIAMOND
10
- //! js-export: valueToYPx, valueToYPxScaled, pointDrawsBar
11
- // `valueToYPx` is `valueScale`'s; it is lifted here, once, for every consumer
12
- // of the scale — the bar shape's painter and hit test import this twin too.
10
+ //! js-export: valueToYPxScaled, pointDrawsBar, pointYPx
11
+ // `valueScale`'s twin is lifted here, once, for the bar shape too.
13
12
 
14
13
  import antialias;
15
14
  import hpmath;
@@ -26,6 +25,7 @@ struct PointMarkInstance {
26
25
  float y : ATTR2;
27
26
  uint color : ATTR3;
28
27
  uint glyph : ATTR4;
28
+ uint row : ATTR5;
29
29
  };
30
30
 
31
31
  struct Uniforms {
@@ -43,6 +43,12 @@ struct Uniforms {
43
43
  float zero;
44
44
  float viewportWidth;
45
45
  float radiusPx;
46
+ // CSS px per row band, the value scale ruling each on its own; the canvas
47
+ // height where every instance is on row 0 (ADR-126).
48
+ float rowHeight;
49
+ // Ends of the value range, inset by `glyphPaint`'s `pointInsetPx` where the
50
+ // display wants its edge glyphs whole; 0 centres a point on the plot's edge.
51
+ float insetPx;
46
52
  // Read by the glyph pad alone; every other length in this block is CSS px.
47
53
  float devicePixelRatio;
48
54
  };
@@ -92,6 +98,13 @@ static const float INV_SQRT5 = 0.4472136;
92
98
  // colour swap. LocusZoom's lead-SNP convention, generalized.
93
99
  static const float DIAMOND_GLYPH_SCALE = 1.6;
94
100
 
101
+ // The shape's own placement: the vertex branch, the Canvas2D painter, the ink
102
+ // box and the hit test all read a value's y through this.
103
+ float pointYPx(float value, float domainMin, float domainMax, float h, int scaleType, float insetPx) {
104
+ float inset = min(insetPx, h * 0.5);
105
+ return inset + valueToYPxScaled(value, domainMin, domainMax, h - 2.0 * inset, scaleType);
106
+ }
107
+
95
108
  // The glyph channel's values. The numbering is a contract between whatever
96
109
  // packs the channel, the Canvas2D painter and the branches below, so it is
97
110
  // authored once here and `//! export-consts`ed.
@@ -110,7 +123,7 @@ VsOut vs_main(PointMarkInstance inst, uint vid : SV_VertexID) {
110
123
 
111
124
  float startClipX = bpToClipX(inst.x, u);
112
125
  float endClipX = bpToClipX(inst.x2, u);
113
- float yPx = valueToYPxScaled(inst.y, u.domainMin, u.domainMax, u.canvasHeight, u.valueScaleType);
126
+ float yPx = u.rowHeight * float(inst.row) + pointYPx(inst.y, u.domainMin, u.domainMax, u.rowHeight, u.valueScaleType, u.insetPx);
114
127
  float centerClipY = yPxToClipY(yPx, u.canvasHeight);
115
128
 
116
129
  // Genomic span in CSS px (clip width spans -1..1 across viewportWidth).
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from pointMark.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) bpRangeX_0 : vec3<f32>,\n @align(4) canvasHeight_0 : f32,\n @align(16) domainMin_0 : f32,\n @align(4) domainMax_0 : f32,\n @align(8) valueScaleType_0 : i32,\n @align(4) rampMode_0 : i32,\n @align(16) rampMin_0 : f32,\n @align(4) rampMax_0 : f32,\n @align(8) zero_0 : f32,\n @align(4) viewportWidth_0 : f32,\n @align(16) radiusPx_0 : f32,\n @align(4) rowHeight_0 : f32,\n @align(8) insetPx_0 : f32,\n @align(4) devicePixelRatio_0 : f32,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : Uniforms_std140_0;\n@binding(2) @group(0) var colorRamp_texture_0 : texture_2d<f32>;\n\n@binding(3) @group(0) var colorRamp_sampler_0 : sampler;\n\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_0 : f32) -> f32\n{\n var step_0 : f32 = 2.0f / bpRange_0.z;\n var _S5 : f32 = - (1.0f / hpZero_0);\n return dot(vec3<f32>(-1.0f, max(splitPos_0.x - bpRange_0.x, _S5), max(splitPos_0.y - bpRange_0.y, _S5)), vec3<f32>(1.0f, step_0, step_0));\n}\n\nfn bpToClipX_0( bp_0 : u32, u_1 : ptr<function, Uniforms_std140_0>) -> f32\n{\n return hpToClipX_0(hpSplitUint_0(bp_0), (*u_1).bpRangeX_0, (*u_1).zero_0);\n}\n\nfn log1pf_0( x_0 : f32) -> f32\n{\n var u_2 : f32 = 1.0f + x_0;\n var _S6 : f32;\n if(u_2 == 1.0f)\n {\n _S6 = x_0;\n }\n else\n {\n _S6 = log(u_2) * (x_0 / (u_2 - 1.0f));\n }\n return _S6;\n}\n\nfn symlogTransform_0( x_1 : f32, c_0 : f32) -> f32\n{\n return f32((i32(sign((x_1))))) * log1pf_0(abs(x_1 / c_0));\n}\n\nfn normalizeScore_0( score_0 : f32, domainMin_1 : f32, domainMax_1 : f32, scaleType_0 : i32, symlogConstant_0 : f32) -> f32\n{\n var tMax_0 : f32;\n var tMin_0 : f32;\n var t_0 : f32;\n if(scaleType_0 == i32(2))\n {\n var _S7 : f32 = symlogTransform_0(score_0, symlogConstant_0);\n var _S8 : f32 = symlogTransform_0(domainMin_1, symlogConstant_0);\n tMax_0 = symlogTransform_0(domainMax_1, symlogConstant_0);\n tMin_0 = _S8;\n t_0 = _S7;\n }\n else\n {\n if(scaleType_0 == i32(1))\n {\n if(domainMin_1 > 0.0f)\n {\n tMax_0 = domainMin_1;\n }\n else\n {\n tMax_0 = 1.0f;\n }\n var _S9 : f32 = log2(max(score_0, tMax_0));\n var _S10 : f32 = log2(tMax_0);\n tMax_0 = log2(max(domainMax_1, tMax_0));\n tMin_0 = _S10;\n t_0 = _S9;\n }\n else\n {\n tMax_0 = domainMax_1;\n tMin_0 = domainMin_1;\n t_0 = score_0;\n }\n }\n var tRange_0 : f32 = tMax_0 - tMin_0;\n if(tRange_0 <= 0.0f)\n {\n if(t_0 > tMin_0)\n {\n tMax_0 = 1.0f;\n }\n else\n {\n tMax_0 = 0.0f;\n }\n return tMax_0;\n }\n return clamp((t_0 - tMin_0) / tRange_0, 0.0f, 1.0f);\n}\n\nfn valueToYPxScaled_0( value_1 : f32, domainMin_2 : f32, domainMax_2 : f32, h_0 : f32, scaleType_1 : i32) -> f32\n{\n return (1.0f - normalizeScore_0(value_1, domainMin_2, domainMax_2, scaleType_1, 1.0f)) * h_0;\n}\n\nfn pointYPx_0( value_2 : f32, domainMin_3 : f32, domainMax_3 : f32, h_1 : f32, scaleType_2 : i32, insetPx_1 : f32) -> f32\n{\n var _S11 : f32 = min(insetPx_1, h_1 * 0.5f);\n return _S11 + valueToYPxScaled_0(value_2, domainMin_3, domainMax_3, h_1 - 2.0f * _S11, scaleType_2);\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 clipLenToPx_0( clipLen_0 : f32, size_0 : f32) -> f32\n{\n return clipLen_0 * 0.5f * size_0;\n}\n\nfn pointDrawsBar_0( spanPx_0 : f32, radiusPx_1 : f32) -> bool\n{\n return spanPx_0 > (radiusPx_1 * 2.0f);\n}\n\nfn unpackRGBA_0( c_1 : u32) -> vec4<f32>\n{\n return vec4<f32>(f32((((c_1 >> (u32(0)))) & (u32(255)))), f32((((c_1 >> (u32(8)))) & (u32(255)))), f32((((c_1 >> (u32(16)))) & (u32(255)))), f32((((c_1 >> (u32(24)))) & (u32(255))))) / vec4<f32>(255.0f);\n}\n\nfn rampColor_0( ramp_texture_0 : texture_2d<f32>, ramp_sampler_0 : sampler, t_1 : f32) -> vec4<f32>\n{\n return (textureSampleLevel((ramp_texture_0), (ramp_sampler_0), (vec2<f32>((clamp(t_1, 0.0f, 1.0f) * 255.0f + 0.5f) / 256.0f, 0.5f)), (0.0f)));\n}\n\nfn markInstanceColor_0( ramp_texture_1 : texture_2d<f32>, ramp_sampler_1 : sampler, packed_0 : u32, rampMode_1 : i32, rampMin_1 : f32, rampMax_1 : f32) -> vec4<f32>\n{\n if(rampMode_1 == i32(0))\n {\n return unpackRGBA_0(packed_0);\n }\n var scaleType_3 : i32;\n if(rampMode_1 == i32(2))\n {\n scaleType_3 = i32(1);\n }\n else\n {\n scaleType_3 = i32(0);\n }\n return rampColor_0(ramp_texture_1, ramp_sampler_1, normalizeScore_0((bitcast<f32>((packed_0))), rampMin_1, rampMax_1, scaleType_3, 1.0f));\n}\n\nfn pxToClipLen_0( px_0 : f32, size_1 : f32) -> f32\n{\n return px_0 * 2.0f / size_1;\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 crispSquareTopLeftPx_0( centerPx_0 : f32, diameterPx_0 : f32) -> f32\n{\n return floor(centerPx_0 - diameterPx_0 * 0.5f + 0.5f);\n}\n\nfn crispSquareCornerPx_0( centerPx_1 : vec2<f32>, diameterPx_1 : f32, q_0 : vec2<f32>) -> vec2<f32>\n{\n return vec2<f32>(crispSquareTopLeftPx_0(centerPx_1.x, diameterPx_1), crispSquareTopLeftPx_0(centerPx_1.y, diameterPx_1)) + q_0 * vec2<f32>(diameterPx_1);\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 crispSquareCornerClip_0( centerClipX_0 : f32, centerYPx_0 : f32, diameterPx_2 : f32, q_1 : vec2<f32>, viewportWidth_1 : f32, canvasHeight_2 : f32) -> vec4<f32>\n{\n var vPx_0 : vec2<f32> = crispSquareCornerPx_0(vec2<f32>(clipXToPx_0(centerClipX_0, viewportWidth_1), centerYPx_0), diameterPx_2, q_1);\n return vec4<f32>(pxToClipX_0(vPx_0.x, viewportWidth_1), yPxToClipY_0(vPx_0.y, canvasHeight_2), 0.0f, 1.0f);\n}\n\nfn aaPx_0( dpr_0 : f32) -> f32\n{\n return 1.0f / max(dpr_0, 1.0f);\n}\n\nfn aaHalfPx_0( dpr_1 : f32) -> f32\n{\n return 0.5f * aaPx_0(dpr_1);\n}\n\nfn discExpand_0( radiusPx_2 : f32, dpr_2 : f32) -> f32\n{\n return (radiusPx_2 + aaHalfPx_0(dpr_2)) / max(radiusPx_2, 0.5f);\n}\n\nstruct VsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_0 : vec4<f32>,\n @location(2) localPos_0 : vec2<f32>,\n @interpolate(flat) @location(1) shape_0 : f32,\n};\n\nstruct vertexInput_0\n{\n @location(0) x_2 : u32,\n @location(1) x2_0 : u32,\n @location(2) y_0 : f32,\n @location(3) color_1 : u32,\n @location(4) glyph_0 : u32,\n @location(5) row_0 : u32,\n};\n\n@vertex\nfn vs_main( _S12 : vertexInput_0, @builtin(vertex_index) vid_1 : u32) -> VsOut_0\n{\n var q_2 : vec2<f32> = quadLocal_0(vid_1 % u32(6));\n var local_0 : vec2<f32> = q_2 * vec2<f32>(2.0f) - vec2<f32>(1.0f);\n var xZero_0 : bool = (q_2.x) < 0.5f;\n var _S13 : Uniforms_std140_0 = u_0;\n var _S14 : f32 = bpToClipX_0(_S12.x_2, &(_S13));\n var _S15 : f32 = bpToClipX_0(_S12.x2_0, &(_S13));\n var yPx_1 : f32 = u_0.rowHeight_0 * f32(_S12.row_0) + pointYPx_0(_S12.y_0, u_0.domainMin_0, u_0.domainMax_0, u_0.rowHeight_0, u_0.valueScaleType_0, u_0.insetPx_0);\n var centerClipY_0 : f32 = yPxToClipY_0(yPx_1, u_0.canvasHeight_0);\n var isBar_0 : bool = pointDrawsBar_0(clipLenToPx_0(abs(_S15 - _S14), u_0.viewportWidth_0), u_0.radiusPx_0);\n var o_0 : VsOut_0;\n o_0.color_0 = markInstanceColor_0(colorRamp_texture_0, colorRamp_sampler_0, _S12.color_1, u_0.rampMode_0, u_0.rampMin_0, u_0.rampMax_0);\n var x_3 : f32;\n if(isBar_0)\n {\n if(xZero_0)\n {\n x_3 = min(_S14, _S15);\n }\n else\n {\n x_3 = max(_S14, _S15);\n }\n o_0.position_0 = vec4<f32>(x_3, centerClipY_0 + pxToClipLen_0(local_0.y * u_0.radiusPx_0, u_0.canvasHeight_0), 0.0f, 1.0f);\n o_0.localPos_0 = local_0;\n o_0.shape_0 = 3.0f;\n }\n else\n {\n var _S16 : bool;\n if((_S12.glyph_0) == u32(0))\n {\n _S16 = (u_0.radiusPx_0 * 2.0f) <= 3.0f;\n }\n else\n {\n _S16 = false;\n }\n if(_S16)\n {\n o_0.position_0 = crispSquareCornerClip_0(_S14, yPx_1, u_0.radiusPx_0 * 2.0f, q_2, u_0.viewportWidth_0, u_0.canvasHeight_0);\n o_0.localPos_0 = local_0;\n o_0.shape_0 = 3.0f;\n }\n else\n {\n var expand_0 : f32 = discExpand_0(u_0.radiusPx_0, u_0.devicePixelRatio_0);\n var _S17 : bool = (_S12.glyph_0) == u32(2);\n if(_S17)\n {\n x_3 = 1.60000002384185791f;\n }\n else\n {\n x_3 = 1.0f;\n }\n var halfPx_0 : f32 = u_0.radiusPx_0 * expand_0 * x_3;\n o_0.position_0 = vec4<f32>(_S14 + pxToClipLen_0(local_0.x * halfPx_0, u_0.viewportWidth_0), centerClipY_0 + pxToClipLen_0(local_0.y * halfPx_0, u_0.canvasHeight_0), 0.0f, 1.0f);\n o_0.localPos_0 = local_0 * vec2<f32>(expand_0);\n if((_S12.glyph_0) == u32(1))\n {\n x_3 = 2.0f;\n }\n else\n {\n if(_S17)\n {\n x_3 = 1.0f;\n }\n else\n {\n x_3 = 0.0f;\n }\n }\n o_0.shape_0 = x_3;\n }\n }\n return o_0;\n}\n\nfn discCoverage_0( localPos_1 : vec2<f32>) -> f32\n{\n return 1.0f - length(localPos_1);\n}\n\nfn aaGradient_0( d_0 : f32) -> f32\n{\n return max(length(vec2<f32>(dpdx(d_0), dpdy(d_0))), 0.00000999999974738f);\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 glyphEdgeAlpha_0( coverage_0 : f32) -> f32\n{\n return aaRamp_0(coverage_0, aaGradient_0(coverage_0));\n}\n\nstruct pixelOutput_0\n{\n @location(0) output_0 : vec4<f32>,\n};\n\nstruct pixelInput_0\n{\n @location(0) color_2 : vec4<f32>,\n @location(2) localPos_2 : vec2<f32>,\n @interpolate(flat) @location(1) shape_1 : f32,\n};\n\n@fragment\nfn fs_main( _S18 : pixelInput_0, @builtin(position) position_1 : vec4<f32>) -> pixelOutput_0\n{\n var coverage_1 : f32;\n if((_S18.shape_1) > 2.5f)\n {\n coverage_1 = 1.0f;\n }\n else\n {\n if((_S18.shape_1) > 1.5f)\n {\n var _S19 : f32 = _S18.localPos_2.y;\n var _S20 : f32 = _S18.localPos_2.x;\n coverage_1 = min(1.0f - _S19, min((2.0f * _S20 + _S19 + 1.0f) * 0.44721359014511108f, (-2.0f * _S20 + _S19 + 1.0f) * 0.44721359014511108f));\n }\n else\n {\n if((_S18.shape_1) > 0.5f)\n {\n coverage_1 = 1.0f - (abs(_S18.localPos_2.x) + abs(_S18.localPos_2.y));\n }\n else\n {\n coverage_1 = discCoverage_0(_S18.localPos_2);\n }\n }\n }\n var alpha_0 : f32 = glyphEdgeAlpha_0(coverage_1);\n if(alpha_0 <= 0.0f)\n {\n discard;\n }\n var _S21 : pixelOutput_0 = pixelOutput_0( vec4<f32>(_S18.color_2.xyz, _S18.color_2.w * alpha_0) );\n return _S21;\n}\n\n"
@@ -16,36 +16,57 @@ function _min(a: number, b: number) {
16
16
  return b < a || Number.isNaN(a) ? b : a
17
17
  }
18
18
 
19
+ function log1pf(x: number): number {
20
+ let u = (1.0 + x)
21
+ let _t0: number
22
+ if ((u == 1.0)) {
23
+ _t0 = x
24
+ } else {
25
+ _t0 = (Math.log(u) * (x / (u - 1.0)))
26
+ }
27
+ return _t0
28
+ }
29
+
19
30
  function symlogTransform(x: number, c: number): number {
20
- return ((((Math.sign(x)) | 0)) * Math.log((1.0 + Math.abs((x / c)))))
31
+ return ((((Math.sign(x)) | 0)) * log1pf(Math.abs((x / c))))
21
32
  }
22
33
 
23
34
  export function normalizeScore(score: number, domainMin: number, domainMax: number, scaleType: number, symlogConstant: number): number {
35
+ let tMax: number
36
+ let tMin: number
37
+ let t: number
24
38
  if ((scaleType == 2)) {
25
- let tMin = symlogTransform(domainMin, symlogConstant)
26
- let tRange = (symlogTransform(domainMax, symlogConstant) - tMin)
27
- if ((tRange <= 0.0)) {
28
- return 0.0
39
+ let _t0 = symlogTransform(score, symlogConstant)
40
+ let _t1 = symlogTransform(domainMin, symlogConstant)
41
+ tMax = symlogTransform(domainMax, symlogConstant)
42
+ tMin = _t1
43
+ t = _t0
44
+ } else {
45
+ if ((scaleType == 1)) {
46
+ if ((domainMin > 0.0)) {
47
+ tMax = domainMin
48
+ } else {
49
+ tMax = 1.0
50
+ }
51
+ let _t2 = Math.log2(_max(score, tMax))
52
+ let _t3 = Math.log2(tMax)
53
+ tMax = Math.log2(_max(domainMax, tMax))
54
+ tMin = _t3
55
+ t = _t2
56
+ } else {
57
+ tMax = domainMax
58
+ tMin = domainMin
59
+ t = score
29
60
  }
30
- return _clamp(((symlogTransform(score, symlogConstant) - tMin) / tRange), 0.0, 1.0)
31
61
  }
32
- if ((scaleType == 1)) {
33
- let floorV: number
34
- if ((domainMin > 0.0)) {
35
- floorV = domainMin
62
+ let tRange = (tMax - tMin)
63
+ if ((tRange <= 0.0)) {
64
+ if ((t > tMin)) {
65
+ tMax = 1.0
36
66
  } else {
37
- floorV = 1.0
38
- }
39
- let logMin = Math.log2(floorV)
40
- let logRange = (Math.log2(_max(domainMax, floorV)) - logMin)
41
- if ((logRange <= 0.0)) {
42
- return 0.0
67
+ tMax = 0.0
43
68
  }
44
- return _clamp(((Math.log2(_max(score, floorV)) - logMin) / logRange), 0.0, 1.0)
45
- }
46
- let range = (domainMax - domainMin)
47
- if ((range <= 0.0)) {
48
- return 0.0
69
+ return tMax
49
70
  }
50
- return _clamp(((score - domainMin) / range), 0.0, 1.0)
71
+ return _clamp(((t - tMin) / tRange), 0.0, 1.0)
51
72
  }
@@ -1,69 +1,53 @@
1
- // The score → [0,1] normalizer every score-scaled track is placed by, and the
2
- // scale-type vocabulary its branches switch on.
1
+ // The score → [0,1] normalizer every score-scaled mark is placed and coloured
2
+ // by — wiggle, the coverage band, the bar and point shapes, their ramps — and
3
+ // the scale-type vocabulary its branches switch on. `makeScoreNormalizer`
4
+ // (render-core's scoreScale.ts) is its loop-hoisted twin.
3
5
  //
4
- // Two real consumers with non-obvious math, which is ADR-040's bar: the wiggle
5
- // renderer's four modes (`wiggleCommon.slang`, via `scoreToY`) and the coverage
6
- // band's depth axis (`coverageBand.slang`, via `normalizeDepthScalar`). They
7
- // carried a branch-for-branch copy each, and the copies did not agree: the
8
- // coverage one compared `scaleType` against bare 2 and 1 rather than the
9
- // constants below, and answered 0 on a degenerate domain where wiggle's divided
10
- // by a 1e-6 floor and saturated. This module is one answer to both.
11
- //
12
- // The degenerate domain answers 0, which is what the JS twin
13
- // (`makeScoreNormalizer`, packages/wiggle-core/src/normalize.ts) has always
14
- // answered. Returning 0 avoids the NaN the 1e-6 floor was there for just as
15
- // well, so the divergence bought nothing and cost a documented exception.
16
- //
17
- // `SCALE_TYPE_LINEAR` is deliberately absent: it is "neither of these", and a
18
- // third constant would be a value nothing compares against.
6
+ // A domain with no range is a step: a score above its min maps to 1 and any
7
+ // other to 0, so a score above a pinned domain sits off the top everywhere.
19
8
  //! export-consts: SCALE_TYPE_LOG, SCALE_TYPE_SYMLOG
20
9
  //! js-export: normalizeScore
21
- //! js-skip: symlogTransform — the JS twin (wiggle-core normalize.ts) spells it Math.log1p, which is accurate near zero where the shader's log(1.0 + x) is not; a generated twin would be a faithful copy of the worse of the two. What both backends must agree on is normalizeScore, which is exported and swept by normalizeScoreParity.test.ts
10
+ //! js-skip: log1pf — JS has Math.log1p, so a twin of this would be the float32 workaround spelled out where the language already answers it
11
+ //! js-skip: symlogTransform — render-core scoreScale.ts reaches Math.log1p directly, one call inside a normalizer it hoists the whole log domain out of, so a per-call twin of this would have no caller. What both backends must agree on is normalizeScore, which is exported and swept by normalizeScoreParity.test.ts
22
12
  module scoreScale;
23
13
 
24
- // The values the `scaleType` uniform is compared against. Emitted into
25
- // @jbrowse/wiggle-core through `wiggleCommon.slang`'s `export-consts` — the
26
- // constant evaluator resolves through imports, and wiggle-core is where
27
- // `WiggleScaleType` is declared, so the numbers stay next to the type they
28
- // name rather than next to the module that happens to author them.
14
+ // `ScaleTypeCode` in scoreScale.ts is these two and 0, for linear.
29
15
  public static const int SCALE_TYPE_LOG = 1;
30
16
  public static const int SCALE_TYPE_SYMLOG = 2;
31
17
 
18
+ // log(1 + x) for x that `1.0 + x` rounds away: a symlog domain narrower than
19
+ // its constant lands entirely in that region, and in float32 the rounding
20
+ // survives the normalize's divide by a tiny domain range — 0.2px of a 40px row
21
+ // on domain [-1, 0.75] with constant 100.5, against the Canvas2D twin's
22
+ // Math.log1p. Kahan's identity: `u - 1.0` is exact where `u` is near 1, so the
23
+ // ratio is the correction the sum lost.
24
+ float log1pf(float x) {
25
+ float u = 1.0 + x;
26
+ return u == 1.0 ? x : log(u) * (x / (u - 1.0));
27
+ }
28
+
32
29
  public float symlogTransform(float x, float c) {
33
- return sign(x) * log(1.0 + abs(x / c));
30
+ return sign(x) * log1pf(abs(x / c));
34
31
  }
35
32
 
36
33
  public float normalizeScore(float score, float domainMin, float domainMax, int scaleType, float symlogConstant) {
34
+ float t = score;
35
+ float tMin = domainMin;
36
+ float tMax = domainMax;
37
37
  if (scaleType == SCALE_TYPE_SYMLOG) {
38
- // Defined at and either side of zero, so unlike the log branch there is
39
- // nothing to floor: the domain arrives as-is and 0 lands where it belongs
40
- // instead of on the baseline with everything else below the floor. On a
41
- // coverage band that is the whole reason symlog is offered — a depth of 0
42
- // is real, common, and what log cannot separate from a depth of 1.
43
- float tMin = symlogTransform(domainMin, symlogConstant);
44
- float tMax = symlogTransform(domainMax, symlogConstant);
45
- float tRange = tMax - tMin;
46
- if (tRange <= 0.0) { return 0.0; }
47
- float t = symlogTransform(score, symlogConstant);
48
- return clamp((t - tMin) / tRange, 0.0, 1.0);
49
- }
50
- if (scaleType == SCALE_TYPE_LOG) {
51
- // Floor at the domain's own min, not at 1, so a domain sitting entirely
52
- // below 1 (mappability, a methylation fraction, any normalized ratio) still
53
- // has a range to spread over instead of collapsing to a flat baseline. Same
54
- // rule and same reasoning as JS `makeScoreNormalizer`, which keeps its own
55
- // hand-written copy because it hoists this arithmetic out of a per-feature
56
- // loop — so this one is `//! js-export`ed as the ORACLE the two are swept
57
- // against (`normalizeScoreParity.test.ts`), not to retire it.
38
+ t = symlogTransform(score, symlogConstant);
39
+ tMin = symlogTransform(domainMin, symlogConstant);
40
+ tMax = symlogTransform(domainMax, symlogConstant);
41
+ } else if (scaleType == SCALE_TYPE_LOG) {
42
+ // The domain's own min, so a domain entirely below 1 still spreads.
58
43
  float floorV = domainMin > 0.0 ? domainMin : 1.0;
59
- float logMin = log2(floorV);
60
- float logMax = log2(max(domainMax, floorV));
61
- float logRange = logMax - logMin;
62
- if (logRange <= 0.0) { return 0.0; }
63
- float logScore = log2(max(score, floorV));
64
- return clamp((logScore - logMin) / logRange, 0.0, 1.0);
44
+ t = log2(max(score, floorV));
45
+ tMin = log2(floorV);
46
+ tMax = log2(max(domainMax, floorV));
47
+ }
48
+ float tRange = tMax - tMin;
49
+ if (tRange <= 0.0) {
50
+ return t > tMin ? 1.0 : 0.0;
65
51
  }
66
- float range = domainMax - domainMin;
67
- if (range <= 0.0) { return 0.0; }
68
- return clamp((score - domainMin) / range, 0.0, 1.0);
52
+ return clamp((t - tMin) / tRange, 0.0, 1.0);
69
53
  }
@@ -1,10 +1,11 @@
1
1
  // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from spanMark.slang.
2
2
  // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
3
 
4
- export const WGSL_SOURCE = "struct RowRectUniforms_std140_0\n{\n @align(16) bpRangeX_0 : vec3<f32>,\n @align(4) canvasHeight_0 : f32,\n @align(16) minCellDenomPx_0 : f32,\n @align(4) minCellPx_0 : f32,\n @align(8) zero_0 : f32,\n @align(4) rowHeight_0 : f32,\n @align(16) rowProportion_0 : f32,\n @align(4) scrollTop_0 : f32,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : RowRectUniforms_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 drawnRowHeightPx_0( rowHeight_1 : f32, rowProportion_1 : f32) -> f32\n{\n return max(rowHeight_1 * rowProportion_1, 1.0f);\n}\n\nfn rowBandOffsetPx_0( rowHeight_2 : f32, rowProportion_2 : f32) -> f32\n{\n return (rowHeight_2 - drawnRowHeightPx_0(rowHeight_2, rowProportion_2)) * 0.5f;\n}\n\nstruct RowBand_0\n{\n height_0 : f32,\n offset_0 : f32,\n};\n\nfn rowBandPx_0( rowHeight_3 : f32, rowProportion_3 : f32) -> RowBand_0\n{\n var band_0 : RowBand_0;\n band_0.height_0 = drawnRowHeightPx_0(rowHeight_3, rowProportion_3);\n band_0.offset_0 = rowBandOffsetPx_0(rowHeight_3, rowProportion_3);\n return band_0;\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_0 : f32) -> f32\n{\n var step_0 : f32 = 2.0f / bpRange_0.z;\n var _S5 : f32 = - (1.0f / hpZero_0);\n return dot(vec3<f32>(-1.0f, max(splitPos_0.x - bpRange_0.x, _S5), max(splitPos_0.y - bpRange_0.y, _S5)), vec3<f32>(1.0f, step_0, step_0));\n}\n\nfn extendToMinWidthPx_0( x1_0 : f32, x2_0 : f32, minWidth_0 : f32) -> f32\n{\n var dx_0 : f32 = x2_0 - x1_0;\n var _S6 : f32;\n if((abs(dx_0)) < minWidth_0)\n {\n if(dx_0 < 0.0f)\n {\n _S6 = - minWidth_0;\n }\n else\n {\n _S6 = minWidth_0;\n }\n _S6 = x1_0 + _S6;\n }\n else\n {\n _S6 = x2_0;\n }\n return _S6;\n}\n\nfn extendToMinWidthX_0( x1_1 : f32, x2_1 : f32, minWidthPx_0 : f32, canvasWidth_0 : f32) -> f32\n{\n return extendToMinWidthPx_0(x1_1, x2_1, minWidthPx_0 * 2.0f / canvasWidth_0);\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 rowRectClipPos_0( startBp_0 : u32, endBp_0 : u32, rowIndex_0 : f32, vid_1 : u32, u_1 : ptr<function, RowRectUniforms_std140_0>) -> vec4<f32>\n{\n var local_0 : vec2<f32> = quadLocal_0(vid_1);\n var band_1 : RowBand_0 = rowBandPx_0((*u_1).rowHeight_0, (*u_1).rowProportion_0);\n var rowY_0 : f32 = band_1.offset_0 + (*u_1).rowHeight_0 * rowIndex_0 - (*u_1).scrollTop_0;\n var sx1_0 : f32 = hpToClipX_0(hpSplitUint_0(startBp_0), (*u_1).bpRangeX_0, (*u_1).zero_0);\n return vec4<f32>(mix(sx1_0, extendToMinWidthX_0(sx1_0, hpToClipX_0(hpSplitUint_0(endBp_0), (*u_1).bpRangeX_0, (*u_1).zero_0), (*u_1).minCellPx_0, (*u_1).minCellDenomPx_0), local_0.x), yPxToClipY_0(mix(rowY_0, rowY_0 + band_1.height_0, local_0.y), (*u_1).canvasHeight_0), 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\nstruct RowRectVsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_0 : vec4<f32>,\n};\n\nstruct RowRectInstance_0\n{\n x_0 : u32,\n x2_2 : u32,\n row_0 : u32,\n color_1 : u32,\n};\n\nfn rowRectVertex_0( inst_0 : RowRectInstance_0, vid_2 : u32, u_2 : ptr<function, RowRectUniforms_std140_0>) -> RowRectVsOut_0\n{\n var o_0 : RowRectVsOut_0;\n var _S7 : vec4<f32> = rowRectClipPos_0(inst_0.x_0, inst_0.x2_2, f32(inst_0.row_0), vid_2, &((*u_2)));\n o_0.position_0 = _S7;\n o_0.color_0 = unpackRGBA_0(inst_0.color_1);\n return o_0;\n}\n\nstruct vertexInput_0\n{\n @location(0) x_1 : u32,\n @location(1) x2_3 : u32,\n @location(2) row_1 : u32,\n @location(3) color_2 : u32,\n};\n\n@vertex\nfn vs_main( _S8 : vertexInput_0, @builtin(vertex_index) vid_3 : u32) -> RowRectVsOut_0\n{\n var _S9 : RowRectInstance_0 = RowRectInstance_0( _S8.x_1, _S8.x2_3, _S8.row_1, _S8.color_2 );\n var _S10 : RowRectUniforms_std140_0 = u_0;\n var _S11 : RowRectVsOut_0 = rowRectVertex_0(_S9, vid_3, &(_S10));\n return _S11;\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};\n\n@fragment\nfn fs_main( _S12 : pixelInput_0, @builtin(position) position_1 : vec4<f32>) -> pixelOutput_0\n{\n var _S13 : pixelOutput_0 = pixelOutput_0( _S12.color_3 );\n return _S13;\n}\n\n"
5
-
6
- export const GLSL_VERTEX = "#version 300 es\nprecision highp float;\nprecision highp int;\nstruct RowRectUniforms_0\n{\n vec3 bpRangeX_0;\n float canvasHeight_0;\n float minCellDenomPx_0;\n float minCellPx_0;\n float zero_0;\n float rowHeight_0;\n float rowProportion_0;\n float scrollTop_0;\n};\n\n\nlayout(std140) uniform Uniforms\n{\n vec3 bpRangeX_0;\n float canvasHeight_0;\n float minCellDenomPx_0;\n float minCellPx_0;\n float zero_0;\n float rowHeight_0;\n float rowProportion_0;\n float scrollTop_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\nfloat drawnRowHeightPx_0(float rowHeight_1, float rowProportion_1)\n{\n\n return max(rowHeight_1 * rowProportion_1, 1.0);\n}\n\nfloat rowBandOffsetPx_0(float rowHeight_2, float rowProportion_2)\n{\n\n return (rowHeight_2 - drawnRowHeightPx_0(rowHeight_2, rowProportion_2)) * 0.5;\n}\n\n\nstruct RowBand_0\n{\n float height_0;\n float offset_0;\n};\n\n\nRowBand_0 rowBandPx_0(float rowHeight_3, float rowProportion_3)\n{\n\n RowBand_0 band_0;\n band_0.height_0 = drawnRowHeightPx_0(rowHeight_3, rowProportion_3);\n band_0.offset_0 = rowBandOffsetPx_0(rowHeight_3, rowProportion_3);\n return band_0;\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_0)\n{\n float step_0 = 2.0 / bpRange_0.z;\n float _S5 = - (1.0 / hpZero_0);\n\n return dot(vec3(-1.0, max(splitPos_0.x - bpRange_0.x, _S5), max(splitPos_0.y - bpRange_0.y, _S5)), vec3(1.0, step_0, step_0));\n}\n\n\nfloat extendToMinWidthPx_0(float x1_0, float x2_0, float minWidth_0)\n{\n\n float dx_0 = x2_0 - x1_0;\n\n float _S6;\n if((abs(dx_0)) < minWidth_0)\n {\n\n if(dx_0 < 0.0)\n {\n\n _S6 = - minWidth_0;\n\n }\n else\n {\n\n _S6 = minWidth_0;\n\n }\n\n _S6 = x1_0 + _S6;\n\n }\n else\n {\n\n _S6 = x2_0;\n\n }\n\n return _S6;\n}\n\nfloat extendToMinWidthX_0(float x1_1, float x2_1, float minWidthPx_0, float canvasWidth_0)\n{\n\n return extendToMinWidthPx_0(x1_1, x2_1, minWidthPx_0 * 2.0 / canvasWidth_0);\n}\n\n\nfloat yPxToClipY_0(float yPx_0, float canvasHeight_1)\n{\n\n return 1.0 - yPx_0 / canvasHeight_1 * 2.0;\n}\n\n\nvec4 rowRectClipPos_0(uint startBp_0, uint endBp_0, float rowIndex_0, uint vid_1, RowRectUniforms_0 u_1)\n{\n\n vec2 local_0 = quadLocal_0(vid_1);\n\n RowBand_0 band_1 = rowBandPx_0(u_1.rowHeight_0, u_1.rowProportion_0);\n float rowY_0 = band_1.offset_0 + u_1.rowHeight_0 * rowIndex_0 - u_1.scrollTop_0;\n\n float sx1_0 = hpToClipX_0(hpSplitUint_0(startBp_0), u_1.bpRangeX_0, u_1.zero_0);\n\n return vec4(mix(sx1_0, extendToMinWidthX_0(sx1_0, hpToClipX_0(hpSplitUint_0(endBp_0), u_1.bpRangeX_0, u_1.zero_0), u_1.minCellPx_0, u_1.minCellDenomPx_0), local_0.x), yPxToClipY_0(mix(rowY_0, rowY_0 + band_1.height_0, local_0.y), u_1.canvasHeight_0), 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\nstruct RowRectVsOut_0\n{\n vec4 position_0;\n vec4 color_0;\n};\n\n\nstruct RowRectInstance_0\n{\n uint x_0;\n uint x2_2;\n uint row_0;\n uint color_1;\n};\n\n\nRowRectVsOut_0 rowRectVertex_0(RowRectInstance_0 inst_0, uint vid_2, RowRectUniforms_0 u_2)\n{\n\n RowRectVsOut_0 o_0;\n o_0.position_0 = rowRectClipPos_0(inst_0.x_0, inst_0.x2_2, float(inst_0.row_0), vid_2, u_2);\n o_0.color_0 = unpackRGBA_0(inst_0.color_1);\n return o_0;\n}\n\n\nout vec4 v_color;\n\n\nlayout(location = 0)\nin uint a_x;\n\n\nlayout(location = 1)\nin uint a_x2;\n\n\nlayout(location = 2)\nin uint a_row;\n\n\nlayout(location = 3)\nin uint a_color;\n\n\nvoid main()\n{\n\n RowRectUniforms_0 _S7 = RowRectUniforms_0(u_0.bpRangeX_0, u_0.canvasHeight_0, u_0.minCellDenomPx_0, u_0.minCellPx_0, u_0.zero_0, u_0.rowHeight_0, u_0.rowProportion_0, u_0.scrollTop_0);\n\n RowRectInstance_0 _S8 = RowRectInstance_0(a_x, a_x2, a_row, a_color);\n RowRectVsOut_0 _S9 = rowRectVertex_0(_S8, uint(gl_VertexID), _S7);\n\n gl_Position = _S9.position_0;\n\n v_color = _S9.color_0;\n\n return;\n}\n\n"
7
-
8
- 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"
4
+ import type { ShaderSource } from '@jbrowse/render-core/hal'
9
5
 
10
6
  export * from './spanMark.iface.generated.ts'
7
+
8
+ export const SOURCE: ShaderSource = {
9
+ wgsl: () => import('./spanMark.wgsl.generated.ts'),
10
+ glsl: () => import('./spanMark.glsl.generated.ts'),
11
+ }
@@ -0,0 +1,6 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from spanMark.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const GLSL_VERTEX = "#version 300 es\nprecision highp float;\nprecision highp int;\nstruct RowRectUniforms_0\n{\n vec3 bpRangeX_0;\n float canvasHeight_0;\n float minCellDenomPx_0;\n float minCellPx_0;\n float zero_0;\n float rowHeight_0;\n float rowProportion_0;\n float scrollTop_0;\n};\n\n\nlayout(std140) uniform Uniforms\n{\n vec3 bpRangeX_0;\n float canvasHeight_0;\n float minCellDenomPx_0;\n float minCellPx_0;\n float zero_0;\n float rowHeight_0;\n float rowProportion_0;\n float scrollTop_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\nfloat drawnRowHeightPx_0(float rowHeight_1, float rowProportion_1)\n{\n\n return max(rowHeight_1 * rowProportion_1, 1.0);\n}\n\nfloat rowBandOffsetPx_0(float rowHeight_2, float rowProportion_2)\n{\n\n return (rowHeight_2 - drawnRowHeightPx_0(rowHeight_2, rowProportion_2)) * 0.5;\n}\n\n\nstruct RowBand_0\n{\n float height_0;\n float offset_0;\n};\n\n\nRowBand_0 rowBandPx_0(float rowHeight_3, float rowProportion_3)\n{\n\n RowBand_0 band_0;\n band_0.height_0 = drawnRowHeightPx_0(rowHeight_3, rowProportion_3);\n band_0.offset_0 = rowBandOffsetPx_0(rowHeight_3, rowProportion_3);\n return band_0;\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_0)\n{\n float step_0 = 2.0 / bpRange_0.z;\n float _S5 = - (1.0 / hpZero_0);\n\n return dot(vec3(-1.0, max(splitPos_0.x - bpRange_0.x, _S5), max(splitPos_0.y - bpRange_0.y, _S5)), vec3(1.0, step_0, step_0));\n}\n\n\nfloat extendToMinWidthPx_0(float x1_0, float x2_0, float minWidth_0)\n{\n\n float dx_0 = x2_0 - x1_0;\n\n float _S6;\n if((abs(dx_0)) < minWidth_0)\n {\n\n if(dx_0 < 0.0)\n {\n\n _S6 = - minWidth_0;\n\n }\n else\n {\n\n _S6 = minWidth_0;\n\n }\n\n _S6 = x1_0 + _S6;\n\n }\n else\n {\n\n _S6 = x2_0;\n\n }\n\n return _S6;\n}\n\nfloat extendToMinWidthX_0(float x1_1, float x2_1, float minWidthPx_0, float canvasWidth_0)\n{\n\n return extendToMinWidthPx_0(x1_1, x2_1, minWidthPx_0 * 2.0 / canvasWidth_0);\n}\n\n\nfloat yPxToClipY_0(float yPx_0, float canvasHeight_1)\n{\n\n return 1.0 - yPx_0 / canvasHeight_1 * 2.0;\n}\n\n\nvec4 rowRectClipPos_0(uint startBp_0, uint endBp_0, float rowIndex_0, uint vid_1, RowRectUniforms_0 u_1)\n{\n\n vec2 local_0 = quadLocal_0(vid_1);\n\n RowBand_0 band_1 = rowBandPx_0(u_1.rowHeight_0, u_1.rowProportion_0);\n float rowY_0 = band_1.offset_0 + u_1.rowHeight_0 * rowIndex_0 - u_1.scrollTop_0;\n\n float sx1_0 = hpToClipX_0(hpSplitUint_0(startBp_0), u_1.bpRangeX_0, u_1.zero_0);\n\n return vec4(mix(sx1_0, extendToMinWidthX_0(sx1_0, hpToClipX_0(hpSplitUint_0(endBp_0), u_1.bpRangeX_0, u_1.zero_0), u_1.minCellPx_0, u_1.minCellDenomPx_0), local_0.x), yPxToClipY_0(mix(rowY_0, rowY_0 + band_1.height_0, local_0.y), u_1.canvasHeight_0), 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\nstruct RowRectVsOut_0\n{\n vec4 position_0;\n vec4 color_0;\n};\n\n\nstruct RowRectInstance_0\n{\n uint x_0;\n uint x2_2;\n uint row_0;\n uint color_1;\n};\n\n\nRowRectVsOut_0 rowRectVertex_0(RowRectInstance_0 inst_0, uint vid_2, RowRectUniforms_0 u_2)\n{\n\n RowRectVsOut_0 o_0;\n o_0.position_0 = rowRectClipPos_0(inst_0.x_0, inst_0.x2_2, float(inst_0.row_0), vid_2, u_2);\n o_0.color_0 = unpackRGBA_0(inst_0.color_1);\n return o_0;\n}\n\n\nout vec4 v_color;\n\n\nlayout(location = 0)\nin uint a_x;\n\n\nlayout(location = 1)\nin uint a_x2;\n\n\nlayout(location = 2)\nin uint a_row;\n\n\nlayout(location = 3)\nin uint a_color;\n\n\nvoid main()\n{\n\n RowRectUniforms_0 _S7 = RowRectUniforms_0(u_0.bpRangeX_0, u_0.canvasHeight_0, u_0.minCellDenomPx_0, u_0.minCellPx_0, u_0.zero_0, u_0.rowHeight_0, u_0.rowProportion_0, u_0.scrollTop_0);\n\n RowRectInstance_0 _S8 = RowRectInstance_0(a_x, a_x2, a_row, a_color);\n RowRectVsOut_0 _S9 = rowRectVertex_0(_S8, uint(gl_VertexID), _S7);\n\n gl_Position = _S9.position_0;\n\n v_color = _S9.color_0;\n\n return;\n}\n\n"
5
+
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"
@@ -4,7 +4,7 @@
4
4
  import type { VertexAttributeLayout, ShaderBinding } from '@jbrowse/render-core/hal'
5
5
 
6
6
  export const BINDINGS: readonly ShaderBinding[] = [
7
- { index: 1, kind: 'uniform', name: 'u' },
7
+ { index: 1, kind: 'uniform', name: 'u', stages: ['vertex'] },
8
8
  ]
9
9
 
10
10
  export const VERTS_PER_INSTANCE = 6
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from spanMark.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const WGSL_SOURCE = "struct RowRectUniforms_std140_0\n{\n @align(16) bpRangeX_0 : vec3<f32>,\n @align(4) canvasHeight_0 : f32,\n @align(16) minCellDenomPx_0 : f32,\n @align(4) minCellPx_0 : f32,\n @align(8) zero_0 : f32,\n @align(4) rowHeight_0 : f32,\n @align(16) rowProportion_0 : f32,\n @align(4) scrollTop_0 : f32,\n};\n\n@binding(1) @group(0) var<uniform> u_0 : RowRectUniforms_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 drawnRowHeightPx_0( rowHeight_1 : f32, rowProportion_1 : f32) -> f32\n{\n return max(rowHeight_1 * rowProportion_1, 1.0f);\n}\n\nfn rowBandOffsetPx_0( rowHeight_2 : f32, rowProportion_2 : f32) -> f32\n{\n return (rowHeight_2 - drawnRowHeightPx_0(rowHeight_2, rowProportion_2)) * 0.5f;\n}\n\nstruct RowBand_0\n{\n height_0 : f32,\n offset_0 : f32,\n};\n\nfn rowBandPx_0( rowHeight_3 : f32, rowProportion_3 : f32) -> RowBand_0\n{\n var band_0 : RowBand_0;\n band_0.height_0 = drawnRowHeightPx_0(rowHeight_3, rowProportion_3);\n band_0.offset_0 = rowBandOffsetPx_0(rowHeight_3, rowProportion_3);\n return band_0;\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_0 : f32) -> f32\n{\n var step_0 : f32 = 2.0f / bpRange_0.z;\n var _S5 : f32 = - (1.0f / hpZero_0);\n return dot(vec3<f32>(-1.0f, max(splitPos_0.x - bpRange_0.x, _S5), max(splitPos_0.y - bpRange_0.y, _S5)), vec3<f32>(1.0f, step_0, step_0));\n}\n\nfn extendToMinWidthPx_0( x1_0 : f32, x2_0 : f32, minWidth_0 : f32) -> f32\n{\n var dx_0 : f32 = x2_0 - x1_0;\n var _S6 : f32;\n if((abs(dx_0)) < minWidth_0)\n {\n if(dx_0 < 0.0f)\n {\n _S6 = - minWidth_0;\n }\n else\n {\n _S6 = minWidth_0;\n }\n _S6 = x1_0 + _S6;\n }\n else\n {\n _S6 = x2_0;\n }\n return _S6;\n}\n\nfn extendToMinWidthX_0( x1_1 : f32, x2_1 : f32, minWidthPx_0 : f32, canvasWidth_0 : f32) -> f32\n{\n return extendToMinWidthPx_0(x1_1, x2_1, minWidthPx_0 * 2.0f / canvasWidth_0);\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 rowRectClipPos_0( startBp_0 : u32, endBp_0 : u32, rowIndex_0 : f32, vid_1 : u32, u_1 : ptr<function, RowRectUniforms_std140_0>) -> vec4<f32>\n{\n var local_0 : vec2<f32> = quadLocal_0(vid_1);\n var band_1 : RowBand_0 = rowBandPx_0((*u_1).rowHeight_0, (*u_1).rowProportion_0);\n var rowY_0 : f32 = band_1.offset_0 + (*u_1).rowHeight_0 * rowIndex_0 - (*u_1).scrollTop_0;\n var sx1_0 : f32 = hpToClipX_0(hpSplitUint_0(startBp_0), (*u_1).bpRangeX_0, (*u_1).zero_0);\n return vec4<f32>(mix(sx1_0, extendToMinWidthX_0(sx1_0, hpToClipX_0(hpSplitUint_0(endBp_0), (*u_1).bpRangeX_0, (*u_1).zero_0), (*u_1).minCellPx_0, (*u_1).minCellDenomPx_0), local_0.x), yPxToClipY_0(mix(rowY_0, rowY_0 + band_1.height_0, local_0.y), (*u_1).canvasHeight_0), 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\nstruct RowRectVsOut_0\n{\n @builtin(position) position_0 : vec4<f32>,\n @location(0) color_0 : vec4<f32>,\n};\n\nstruct RowRectInstance_0\n{\n x_0 : u32,\n x2_2 : u32,\n row_0 : u32,\n color_1 : u32,\n};\n\nfn rowRectVertex_0( inst_0 : RowRectInstance_0, vid_2 : u32, u_2 : ptr<function, RowRectUniforms_std140_0>) -> RowRectVsOut_0\n{\n var o_0 : RowRectVsOut_0;\n var _S7 : vec4<f32> = rowRectClipPos_0(inst_0.x_0, inst_0.x2_2, f32(inst_0.row_0), vid_2, &((*u_2)));\n o_0.position_0 = _S7;\n o_0.color_0 = unpackRGBA_0(inst_0.color_1);\n return o_0;\n}\n\nstruct vertexInput_0\n{\n @location(0) x_1 : u32,\n @location(1) x2_3 : u32,\n @location(2) row_1 : u32,\n @location(3) color_2 : u32,\n};\n\n@vertex\nfn vs_main( _S8 : vertexInput_0, @builtin(vertex_index) vid_3 : u32) -> RowRectVsOut_0\n{\n var _S9 : RowRectInstance_0 = RowRectInstance_0( _S8.x_1, _S8.x2_3, _S8.row_1, _S8.color_2 );\n var _S10 : RowRectUniforms_std140_0 = u_0;\n var _S11 : RowRectVsOut_0 = rowRectVertex_0(_S9, vid_3, &(_S10));\n return _S11;\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};\n\n@fragment\nfn fs_main( _S12 : pixelInput_0, @builtin(position) position_1 : vec4<f32>) -> pixelOutput_0\n{\n var _S13 : pixelOutput_0 = pixelOutput_0( _S12.color_3 );\n return _S13;\n}\n\n"
@@ -1,52 +1,15 @@
1
- // The linear value → canvas-y scale a quantitative mark places its datum
2
- // through: clamp into the domain, invert (a bigger value sits higher), scale to
3
- // the canvas. `valueToYPx` is the linear scale on its own, which is what a
4
- // consumer with no scale type of its own reads (Manhattan pins linear, and its
5
- // -log10 p is already a pre-transform); `valueToYPxScaled` below takes a
6
- // declared one.
7
- //
8
- // Two shapes compose it (ADR-095): `pointMark` reads it for a glyph centre and
9
- // `barMark` for both cuts of a bar. Each keeps its own anchor (ADR-097) — a
10
- // point centres on the value, a bar grows from `origin` to it — so only the
11
- // scale lives here.
12
- //
13
- // max(range, 1e-6) guards a degenerate (min == max) domain from dividing by
14
- // zero. JS spelled that guard `|| 1`, and the two are NOT the same: `|| 1`
15
- // invents a phantom unit-wide domain, so with bounds pinned to a single value
16
- // a value half a unit above it drew half-way up the Canvas2D canvas while the
17
- // GPU clamped it to the top. Pinning a degenerate domain means everything above
18
- // it is off the top, which is what this does; the parity test pins the case.
19
- //
20
- // A declared log scale takes the log arm of `scoreScale`'s `normalizeScore`,
21
- // the normalizer wiggle and the coverage band are already placed by, so a mark
22
- // display's axis ticks and its shader agree by construction. The linear arm
23
- // stays this module's own: `normalizeScore` answers 0 on a degenerate domain
24
- // and this answers 1, and that difference is a pinned cross-backend value
25
- // (ADR-097).
26
- //
27
- // The JS twin is lifted by `pointMark.slang`'s `//! js-export` rather than
28
- // here, the way hpmath's `expandToMinWidthPx` reaches JS through
29
- // `coverageBar.slang`: one twin, in the generated module every consumer of the
30
- // scale already imports.
1
+ // A quantitative mark's value → canvas y: `scoreScale`'s normalizer, flipped
2
+ // so a bigger value sits higher. Only the scale lives here; each shape keeps
3
+ // its own anchor (ADR-097). `pointMark.slang` lifts the JS twin.
4
+ //! js-skip: valueToYPx — the linear case of valueToYPxScaled, whose twin pointMark.slang lifts; a shader reading it alone (the score example's scoreBarHeightPx) lifts the caller it sits inside
31
5
  module valueScale;
32
6
 
33
7
  import scoreScale;
34
8
 
35
- public float valueToYPx(float value, float domainMin, float domainMax, float h) {
36
- float norm = clamp(
37
- (value - domainMin) / max(domainMax - domainMin, 1e-6),
38
- 0.0,
39
- 1.0,
40
- );
41
- return (1.0 - norm) * h;
9
+ public float valueToYPxScaled(float value, float domainMin, float domainMax, float h, int scaleType) {
10
+ return (1.0 - normalizeScore(value, domainMin, domainMax, scaleType, 1.0)) * h;
42
11
  }
43
12
 
44
- // The same placement under a declared scale type: `SCALE_TYPE_LOG` reads the
45
- // value through `scoreScale`'s log arm, anything else through the linear one
46
- // above.
47
- public float valueToYPxScaled(float value, float domainMin, float domainMax, float h, int scaleType) {
48
- if (scaleType == SCALE_TYPE_LOG) {
49
- return (1.0 - normalizeScore(value, domainMin, domainMax, SCALE_TYPE_LOG, 1.0)) * h;
50
- }
51
- return valueToYPx(value, domainMin, domainMax, h);
13
+ public float valueToYPx(float value, float domainMin, float domainMax, float h) {
14
+ return valueToYPxScaled(value, domainMin, domainMax, h, 0);
52
15
  }