webgl2-sdf 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +100 -0
  2. package/node/bezier/bezier-curves-to-line-segs.d.ts +10 -0
  3. package/node/bezier/eval-de-casteljau.d.ts +17 -0
  4. package/node/bezier/from-to/from-to-2.d.ts +12 -0
  5. package/node/bezier/from-to/from-to-3.d.ts +12 -0
  6. package/node/bezier/from-to/from-to.d.ts +10 -0
  7. package/node/bezier/is-cubic-obtuse.d.ts +11 -0
  8. package/node/bezier/is-quad-obtuse.d.ts +11 -0
  9. package/node/bezier/is-really-point.d.ts +9 -0
  10. package/node/bezier/split-by-deviation-from-straight-line-cubic.d.ts +20 -0
  11. package/node/bezier/split-by-deviation-from-straight-line-quad.d.ts +11 -0
  12. package/node/bezier/split-into-line-segments.d.ts +10 -0
  13. package/node/debug-shaders.d.ts +9 -0
  14. package/node/generate-sdf.d.ts +18 -0
  15. package/node/helpers/calc-circs.d.ts +11 -0
  16. package/node/helpers/clip-line-segment-to-grid.d.ts +14 -0
  17. package/node/helpers/clip-line-segment-to-strips.d.ts +13 -0
  18. package/node/helpers/create-empty-grid.d.ts +8 -0
  19. package/node/helpers/create-empty-strips.d.ts +7 -0
  20. package/node/helpers/distance-seg-to-p.d.ts +5 -0
  21. package/node/helpers/find-close-cells.d.ts +3 -0
  22. package/node/helpers/find-crossing-cells.d.ts +3 -0
  23. package/node/helpers/get-distance-to-line-function.d.ts +10 -0
  24. package/node/helpers/jump-idx.d.ts +2 -0
  25. package/node/helpers/map-to-viewbox.d.ts +2 -0
  26. package/node/helpers/seg-box-x.d.ts +10 -0
  27. package/node/helpers/seg-strip-x.d.ts +9 -0
  28. package/node/index.d.ts +1 -0
  29. package/node/main-program.d.ts +4 -0
  30. package/node/max-aspect-ratio-before-stretch.d.ts +2 -0
  31. package/node/prepare-buffers.d.ts +10 -0
  32. package/node/row-count.d.ts +2 -0
  33. package/node/shaders/main.fragment.d.ts +2 -0
  34. package/node/shaders/main.vertex.d.ts +2 -0
  35. package/node/svg/get-beziers-from-raw-paths.d.ts +12 -0
  36. package/node/svg/get-paths-from-str.d.ts +9 -0
  37. package/node/svg/path-data-polyfill/parse-number.d.ts +10 -0
  38. package/node/svg/path-data-polyfill/parse-path-data-string.d.ts +9 -0
  39. package/node/svg/path-data-polyfill/source.d.ts +19 -0
  40. package/node/svg/path-segment/c.d.ts +19 -0
  41. package/node/svg/path-segment/h.d.ts +15 -0
  42. package/node/svg/path-segment/l.d.ts +16 -0
  43. package/node/svg/path-segment/q.d.ts +16 -0
  44. package/node/svg/path-segment/s.d.ts +20 -0
  45. package/node/svg/path-segment/t.d.ts +18 -0
  46. package/node/svg/path-segment/v.d.ts +15 -0
  47. package/node/svg/path-segment/z.d.ts +13 -0
  48. package/node/svg/path-state.d.ts +11 -0
  49. package/node/tex-width.d.ts +11 -0
  50. package/node/types/attribute.d.ts +6 -0
  51. package/node/types/cell.d.ts +18 -0
  52. package/node/types/gl-context.d.ts +28 -0
  53. package/node/types/gl-type.d.ts +2 -0
  54. package/node/types/gl-usage.d.ts +2 -0
  55. package/node/types/program.d.ts +16 -0
  56. package/node/types/strip.d.ts +8 -0
  57. package/node/types/texture.d.ts +4 -0
  58. package/node/utils/calc-circs.d.ts +11 -0
  59. package/node/utils/clip-line-segment-to-grid.d.ts +14 -0
  60. package/node/utils/clip-line-segment-to-strips.d.ts +13 -0
  61. package/node/utils/create-empty-grid.d.ts +8 -0
  62. package/node/utils/create-empty-strips.d.ts +7 -0
  63. package/node/utils/distance-seg-to-p.d.ts +5 -0
  64. package/node/utils/find-close-cells.d.ts +3 -0
  65. package/node/utils/find-crossing-cells.d.ts +3 -0
  66. package/node/utils/get-distance-to-line-function.d.ts +10 -0
  67. package/node/utils/jump-idx.d.ts +2 -0
  68. package/node/utils/map-to-viewbox.d.ts +2 -0
  69. package/node/utils/seg-box-x.d.ts +10 -0
  70. package/node/utils/seg-strip-x.d.ts +9 -0
  71. package/node/vector/dot.d.ts +8 -0
  72. package/node/vector/from-to-vec.d.ts +8 -0
  73. package/node/vector/len.d.ts +6 -0
  74. package/node/webgl-utils/compile-shader.d.ts +2 -0
  75. package/node/webgl-utils/get-gl-context.d.ts +10 -0
  76. package/node/webgl-utils/set-attribute.d.ts +15 -0
  77. package/node/webgl-utils/set-uniform-block.d.ts +9 -0
  78. package/node/webgl-utils/set-uniform.d.ts +4 -0
  79. package/node/webgl-utils/uniform-block.d.ts +6 -0
  80. package/node/webgl-utils/uniform-type.d.ts +2 -0
  81. package/node/webgl-utils/use-program.d.ts +17 -0
  82. package/node/webgl-utils/use-texture.d.ts +9 -0
  83. package/node/webgl2.d.ts +2 -0
  84. package/package.json +56 -0
  85. package/src/bezier/bezier-curves-to-line-segs.ts +39 -0
  86. package/src/bezier/eval-de-casteljau.ts +78 -0
  87. package/src/bezier/from-to/from-to-2.ts +159 -0
  88. package/src/bezier/from-to/from-to-3.ts +176 -0
  89. package/src/bezier/from-to/from-to.ts +30 -0
  90. package/src/bezier/is-cubic-obtuse.ts +31 -0
  91. package/src/bezier/is-quad-obtuse.ts +26 -0
  92. package/src/bezier/is-really-point.ts +25 -0
  93. package/src/bezier/split-by-deviation-from-straight-line-cubic.ts +109 -0
  94. package/src/bezier/split-by-deviation-from-straight-line-quad.ts +66 -0
  95. package/src/bezier/split-into-line-segments.ts +39 -0
  96. package/src/debug-shaders.ts +38 -0
  97. package/src/generate-sdf.ts +91 -0
  98. package/src/index.ts +2 -0
  99. package/src/main-program.ts +160 -0
  100. package/src/max-aspect-ratio-before-stretch.ts +5 -0
  101. package/src/prepare-buffers.ts +149 -0
  102. package/src/row-count.ts +6 -0
  103. package/src/shaders/main.fragment.ts +157 -0
  104. package/src/shaders/main.vertex.ts +55 -0
  105. package/src/svg/get-beziers-from-raw-paths.ts +112 -0
  106. package/src/svg/get-paths-from-str.ts +19 -0
  107. package/src/svg/path-data-polyfill/parse-number.ts +138 -0
  108. package/src/svg/path-data-polyfill/parse-path-data-string.ts +26 -0
  109. package/src/svg/path-data-polyfill/source.ts +176 -0
  110. package/src/svg/path-segment/c.ts +34 -0
  111. package/src/svg/path-segment/h.ts +28 -0
  112. package/src/svg/path-segment/l.ts +30 -0
  113. package/src/svg/path-segment/q.ts +30 -0
  114. package/src/svg/path-segment/s.ts +40 -0
  115. package/src/svg/path-segment/t.ts +35 -0
  116. package/src/svg/path-segment/v.ts +28 -0
  117. package/src/svg/path-segment/z.ts +27 -0
  118. package/src/svg/path-state.ts +15 -0
  119. package/src/tex-width.ts +14 -0
  120. package/src/types/attribute.ts +9 -0
  121. package/src/types/cell.ts +21 -0
  122. package/src/types/gl-context.ts +28 -0
  123. package/src/types/gl-type.ts +16 -0
  124. package/src/types/gl-usage.ts +14 -0
  125. package/src/types/program.ts +14 -0
  126. package/src/types/strip.ts +11 -0
  127. package/src/types/texture.ts +7 -0
  128. package/src/types/typed-array.ts +16 -0
  129. package/src/utils/calc-circs.ts +129 -0
  130. package/src/utils/clip-line-segment-to-grid.ts +133 -0
  131. package/src/utils/clip-line-segment-to-strips.ts +196 -0
  132. package/src/utils/create-empty-grid.ts +32 -0
  133. package/src/utils/create-empty-strips.ts +21 -0
  134. package/src/utils/distance-seg-to-p.ts +50 -0
  135. package/src/utils/find-close-cells.ts +171 -0
  136. package/src/utils/find-crossing-cells.ts +40 -0
  137. package/src/utils/get-distance-to-line-function.ts +59 -0
  138. package/src/utils/is-point-in-box.ts +16 -0
  139. package/src/utils/jump-idx.ts +107 -0
  140. package/src/utils/map-to-viewbox.ts +41 -0
  141. package/src/utils/path.ts +137 -0
  142. package/src/utils/seg-box-x.ts +84 -0
  143. package/src/utils/seg-strip-x.ts +72 -0
  144. package/src/utils/sum.ts +13 -0
  145. package/src/vector/dot.ts +13 -0
  146. package/src/vector/from-to-vec.ts +13 -0
  147. package/src/vector/len.ts +11 -0
  148. package/src/webgl-utils/compile-shader.ts +15 -0
  149. package/src/webgl-utils/get-gl-context.ts +61 -0
  150. package/src/webgl-utils/set-attribute.ts +74 -0
  151. package/src/webgl-utils/set-uniform-block.ts +45 -0
  152. package/src/webgl-utils/set-uniform.ts +24 -0
  153. package/src/webgl-utils/uniform-block.ts +9 -0
  154. package/src/webgl-utils/uniform-type.ts +10 -0
  155. package/src/webgl-utils/use-program.ts +48 -0
  156. package/src/webgl-utils/use-texture.ts +34 -0
@@ -0,0 +1,91 @@
1
+ import { getWebGLContext } from './webgl-utils/get-gl-context.js';
2
+ import { main_Vertex } from './shaders/main.vertex.js';
3
+ import { getMainFragment } from './shaders/main.fragment.js';
4
+ import { initProgram } from './webgl-utils/use-program.js';
5
+ import { mainProgram } from './main-program.js';
6
+ import { ROW_COUNT } from './row-count.js';
7
+ import { getPathsFromStr } from './svg/get-paths-from-str.js';
8
+ import { MAX_ASPECT_RATIO_BEFORE_STRETCH } from './max-aspect-ratio-before-stretch.js';
9
+ // import { debugShaders } from './debug-shaders.js';
10
+
11
+ const { ceil, min, max } = Math;
12
+
13
+
14
+ /**
15
+ *
16
+ * @param gl
17
+ * @param psss
18
+ * @param width
19
+ * @param height
20
+ * @param viewbox
21
+ * @param maxDistance
22
+ * @param sdfExponent
23
+ * @param inclInside
24
+ * @param inclOutside
25
+ * @param x
26
+ * @param y
27
+ * @param channel
28
+ * @param resolution
29
+ */
30
+ function generateIntoFramebuffer(
31
+ gl: WebGL2RenderingContext,
32
+ psss: (number[][])[][] | string,
33
+ width: number,
34
+ height: number,
35
+ viewbox: [number,number,number,number],
36
+ maxDistance: number,
37
+ sdfExponent = 1,
38
+ inclInside = true,
39
+ inclOutside = true,
40
+ // framebuffer: WebGLFramebuffer | null,
41
+ x = 0, y = 0,
42
+ channel = 0,
43
+ resolution: 0.5|1 = 0.5) {
44
+
45
+ // debugShaders(gl); // comment for production
46
+
47
+ const psss_ = typeof psss === 'string'
48
+ ? getPathsFromStr(psss)
49
+ : psss;
50
+
51
+ const glContext = getWebGLContext(gl);
52
+
53
+ const { onContextLoss } = glContext;
54
+
55
+ let stretch = 1;
56
+ const aspectRatio = width/height;
57
+ if (aspectRatio > MAX_ASPECT_RATIO_BEFORE_STRETCH) {
58
+ const r = width/MAX_ASPECT_RATIO_BEFORE_STRETCH;
59
+ stretch = r/height;
60
+ height = r;
61
+ }
62
+
63
+ const cellSize = height/ROW_COUNT;
64
+
65
+ const maxDim = max(width, height);
66
+ const colCount = ceil(width/cellSize);
67
+
68
+ const padCount = 2*ceil(min(maxDistance, maxDim)/cellSize/2);
69
+
70
+ const programMain = initProgram(
71
+ glContext, `main${colCount}-${padCount}`,
72
+ main_Vertex, getMainFragment(colCount, padCount)
73
+ );
74
+
75
+ gl.useProgram(programMain.program);
76
+ mainProgram(
77
+ glContext, programMain, resolution, psss_,
78
+ viewbox, maxDistance, sdfExponent, width, height, colCount,
79
+ cellSize, inclInside, inclOutside, padCount, stretch
80
+ );
81
+
82
+ // Handle context loss occurring during any of the above calls
83
+ if (gl.isContextLost()) {
84
+ onContextLoss();
85
+
86
+ throw new Error('Webgl2 context lost.');
87
+ }
88
+ }
89
+
90
+
91
+ export { generateIntoFramebuffer }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { generateIntoFramebuffer } from './generate-sdf.js';
@@ -0,0 +1,160 @@
1
+ import { Program } from './types/program.js';
2
+ import { useTexture } from './webgl-utils/use-texture.js';
3
+ import { setAttribute } from './webgl-utils/set-attribute.js';
4
+ import { setUniform } from './webgl-utils/set-uniform.js';
5
+ import { setUniformBlock } from './webgl-utils/set-uniform-block.js';
6
+ import { GlContext } from './types/gl-context.js';
7
+ import { prepareBuffers } from './prepare-buffers.js';
8
+ import { TEX_WIDTH } from './tex-width.js';
9
+ import { ROW_COUNT } from './row-count.js';
10
+
11
+
12
+ const SEG_TEX_INDEX = 0;
13
+ const CELL_TEX_INDEX = 1;
14
+ const CROSS_TEX_INDEX = 2;
15
+
16
+
17
+ function mainProgram(
18
+ glContext: GlContext,
19
+ programMain: Program,
20
+ resolution: 0.5|1,
21
+ psss: number[][][][],
22
+ viewbox: [number,number,number,number],
23
+ maxDistance: number,
24
+ sdfExponent = 1,
25
+ width: number,
26
+ height: number,
27
+ colCount: number,
28
+ cellSize: number,
29
+ inclInside: boolean,
30
+ inclOutside: boolean,
31
+ padCount: number,
32
+ stretch: number) {
33
+
34
+ const { gl } = glContext;
35
+
36
+ const vertices: number[] = [];
37
+ const x0 = 0;
38
+ const y0 = 0;
39
+ const x1 = 1/ROW_COUNT;
40
+ const y1 = 1/ROW_COUNT;
41
+
42
+ vertices.push(x0,y0, x1,y0, x0,y1); // First triangle: (x0,y0), (x1,y0), (x0,y1)
43
+ vertices.push(x1,y0, x1,y1, x0,y1); // Second triangle: (x1,y0), (x1,y1), (x0,y1)
44
+ const uvArr = new Float32Array(vertices);
45
+
46
+ const setUniform_ = setUniform(programMain);
47
+ const setAttribute_ = setAttribute(programMain);
48
+
49
+ const {
50
+ lineSegPtCoords_Arr, segIdxs_PerCell_Range_Arr,
51
+ closeCellIdxs_PerCell_Arr, closeCellIdxs_PerCell_Range_Arr,
52
+ crossCellIdxs_PerCell_Arr, crossCellIdxs_perCell_Range_Arr,
53
+ segIdxs_PerStrip_Range_Arr
54
+ } = prepareBuffers(
55
+ psss, width, height, colCount, cellSize, maxDistance,
56
+ padCount, resolution, viewbox, stretch
57
+ );
58
+
59
+ // Init/update attributes
60
+ setAttribute_(
61
+ 'aUV', 2, // size, i.e 2d - draw 2 values each time
62
+ gl.FLOAT, gl.STATIC_DRAW, uvArr
63
+ );
64
+
65
+ setAttribute_(
66
+ 'aCrossIdxRangePerCell',
67
+ 2, // count
68
+ gl.INT, gl.STATIC_DRAW, crossCellIdxs_perCell_Range_Arr,
69
+ 1 // instance division (once per instance)
70
+ );
71
+
72
+ setAttribute_(
73
+ 'aCloseCellIdxRangePerCell',
74
+ 2, // count
75
+ gl.INT, gl.STATIC_DRAW, closeCellIdxs_PerCell_Range_Arr,
76
+ 1 // instance division (once per instance)
77
+ );
78
+
79
+ // Init/update uniforms
80
+ setUniform_('2f', 'uWidthHeight', width, height);
81
+ setUniform_('1f', 'uMaxDistance', maxDistance);
82
+ setUniform_('1f', 'uExponent', sdfExponent); // TODO
83
+ setUniform_('1i', 'uIncl', (inclInside ? 1 : 0) + (inclOutside ? 2 : 0));
84
+ setUniform_('1f', 'uStretch', stretch); // TODO
85
+
86
+ setUniformBlock(programMain)('SegIdxRangePerCellBlock', 0, segIdxs_PerCell_Range_Arr);
87
+ setUniformBlock(programMain)('SegIdxRangePerStripBlock', 1, segIdxs_PerStrip_Range_Arr);
88
+
89
+ ///////////////////////////////////////
90
+ // Create buffer for line segment data
91
+ useTexture(glContext, SEG_TEX_INDEX, 'segs');
92
+ gl.texImage2D( // really 1d
93
+ gl.TEXTURE_2D,
94
+ 0, // level - irrelevant
95
+ gl.RGBA32F, // internalFormat - we're using 4 floats for the 2 line segment endpoints
96
+ lineSegPtCoords_Arr.length/4, // width === number of lines
97
+ 1, // height - linear data texture so we only need height of 1
98
+ 0, // border - whatever
99
+ gl.RGBA, // format
100
+ gl.FLOAT, // it holds floats
101
+ lineSegPtCoords_Arr // texture data
102
+ );
103
+ const segTexLoc = gl.getUniformLocation(programMain.program, "uSegs");
104
+ gl.uniform1i(segTexLoc, SEG_TEX_INDEX);
105
+ ///////////////////////////////////////////////
106
+
107
+ ///////////////////////////////////////////////
108
+ // Create buffer for close cell indexes per cell
109
+ useTexture(glContext, CELL_TEX_INDEX, 'closeCellIdxsPerCell');
110
+ gl.texImage2D( // really 1d
111
+ gl.TEXTURE_2D,
112
+ 0, // level - irrelevant
113
+ gl.R32I, // internalFormat - we're using 1 signed 32-bit int for indexes
114
+ TEX_WIDTH, // width === number of indexes
115
+ closeCellIdxs_PerCell_Arr.length / TEX_WIDTH,
116
+ 0, // border - whatever
117
+ gl.RED_INTEGER, // format
118
+ gl.INT, // it holds ints
119
+ closeCellIdxs_PerCell_Arr // texture data
120
+ );
121
+
122
+ const cellTexLoc = gl.getUniformLocation(programMain.program, "uCloseCellIdxs");
123
+ gl.uniform1i(cellTexLoc, CELL_TEX_INDEX);
124
+ ///////////////////////////////////////////////
125
+
126
+ ///////////////////////////////////////////////
127
+ // Create buffer for crossing cell indexes per cell
128
+ useTexture(glContext, CROSS_TEX_INDEX, 'crossCellIdxsPerCell');
129
+ gl.texImage2D( // really 1d
130
+ gl.TEXTURE_2D,
131
+ 0, // level - irrelevant
132
+ gl.R32I, // internalFormat - we're using 1 signed 32-bit int for indexes
133
+ TEX_WIDTH, // width === number of indexes
134
+ crossCellIdxs_PerCell_Arr.length / TEX_WIDTH, // height - linear data texture so we only need height of 1
135
+ 0, // border - whatever
136
+ gl.RED_INTEGER, // format
137
+ gl.INT, // it holds ints
138
+ crossCellIdxs_PerCell_Arr // texture data
139
+ );
140
+ const crossTexLoc = gl.getUniformLocation(programMain.program, "uCrossCellIdxs");
141
+ gl.uniform1i(crossTexLoc, CROSS_TEX_INDEX);
142
+ ///////////////////////////////////////////////
143
+
144
+ if (stretch > 1) {
145
+ gl.enable(gl.SCISSOR_TEST);
146
+ gl.scissor(0, 0, width, height/stretch)
147
+ }
148
+
149
+ gl.viewport(0, 0, width, height);
150
+
151
+ // draw a square colCount * ROW_COUNT times - 6 vertics
152
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, colCount*ROW_COUNT);
153
+
154
+ if (stretch > 1) {
155
+ gl.disable(gl.SCISSOR_TEST);
156
+ }
157
+ }
158
+
159
+
160
+ export { mainProgram }
@@ -0,0 +1,5 @@
1
+
2
+ const MAX_ASPECT_RATIO_BEFORE_STRETCH = 4;
3
+
4
+
5
+ export { MAX_ASPECT_RATIO_BEFORE_STRETCH }
@@ -0,0 +1,149 @@
1
+ import { bezierCurvesToLineSegs } from './bezier/bezier-curves-to-line-segs.js';
2
+ import { findCloseCells } from './utils/find-close-cells.js';
3
+ import { clipLineSegmentToGrid } from './utils/clip-line-segment-to-grid.js';
4
+ import { createEmptyGrid } from './utils/create-empty-grid.js';
5
+ import { findCrossingCells } from './utils/find-crossing-cells.js';
6
+ import { TEX_WIDTH } from './tex-width.js';
7
+ import { ROW_COUNT } from './row-count.js';
8
+ import { createEmptyStrips } from './utils/create-empty-strips.js';
9
+ import { clipLineSegmentToStrips } from './utils/clip-line-segment-to-strips.js';
10
+ import { mapToViewbox } from './utils/map-to-viewbox.js';
11
+ // import { sum } from './utils/sum.js';
12
+
13
+
14
+ function prepareBuffers(
15
+ psss: (number[][])[][],
16
+ width: number,
17
+ height: number,
18
+ colCount: number,
19
+ cellSize: number,
20
+ maxDistance: number,
21
+ padCount: number,
22
+ resolution: 0.5|1 = 0.5,
23
+ viewbox: [number,number,number,number] = [0,0,width,height],
24
+ stretch = 1) {
25
+
26
+ ////////////////////////////////////////////////////////////////////////////
27
+ const psss_ = mapToViewbox(viewbox, width, height/stretch, psss);
28
+
29
+ const lineSegs = bezierCurvesToLineSegs(psss_, resolution);
30
+ const grid = createEmptyGrid(colCount, padCount);
31
+ const strips = createEmptyStrips();
32
+ for (let i=0; i<lineSegs.length; i++) {
33
+ const seg = lineSegs[i];
34
+ // Split the line segment into multiple segments that fit within grid cells
35
+ clipLineSegmentToGrid(grid, width, height, colCount, cellSize, seg, padCount); // add segments to grid
36
+ clipLineSegmentToStrips(strips, height, seg); // add segments to strips
37
+ }
38
+
39
+ findCloseCells(grid, colCount, cellSize, maxDistance, padCount); // add close cells
40
+ findCrossingCells(grid, colCount, padCount); // add crossing cells
41
+ ////////////////////////////////////////////////////////////////////////////
42
+
43
+ const allSegs: number[][][] = [];
44
+ const segIdxs_PerCell_Range: [number,number][] = [];
45
+
46
+ // close cells
47
+ const closeCellIdxs_PerCell: number[] = [];
48
+ const closeCellIdxs_PerCell_Range: [number,number][] = [];
49
+
50
+ // crossing cells
51
+ const crossCellIdxs_PerCell: number[] = [];
52
+ const crossCellIdxs_PerCell_Range: [number,number][] = [];
53
+
54
+ // const closeCellIdxsPerCell_: number[][] = []; // testing
55
+
56
+ let S1 = 0;
57
+ let S2 = 0;
58
+ let S3 = 0;
59
+ for (let i=0; i<colCount + 2*padCount; i++) {
60
+ for (let j=0; j<ROW_COUNT + 2*padCount; j++) {
61
+ const cell = grid[i][j];
62
+
63
+ ///////////
64
+ if (i >= padCount && i < colCount + padCount &&
65
+ j >= padCount && j < ROW_COUNT + padCount) {
66
+
67
+ const { closeCells, crossingCells } = cell;
68
+
69
+ const L1 = crossingCells.length;
70
+ crossCellIdxs_PerCell.push(...crossingCells);
71
+ crossCellIdxs_PerCell_Range.push([S1, L1]);
72
+ S1 += L1;
73
+
74
+ const L2 = closeCells.length;
75
+ closeCellIdxs_PerCell.push(...closeCells);
76
+ closeCellIdxs_PerCell_Range.push([S2, L2]);
77
+ S2 += L2;
78
+
79
+ // closeCellIdxsPerCell_.push(closeCells); // testing
80
+ }
81
+
82
+ //////////
83
+ const { lineSegs } = cell;
84
+
85
+ const L3 = lineSegs.length;
86
+ segIdxs_PerCell_Range.push([S3, L3]);
87
+ S3 += L3;
88
+ allSegs.push(...lineSegs);
89
+ }
90
+ }
91
+
92
+ // It is a requirement to fill in multiples of `TEX_WIDTH`
93
+ while (closeCellIdxs_PerCell.length % TEX_WIDTH !== 0) { closeCellIdxs_PerCell.push(0); }
94
+ while (crossCellIdxs_PerCell.length % TEX_WIDTH !== 0) { crossCellIdxs_PerCell.push(0); }
95
+
96
+ // Add line segs from strips
97
+ const segIdxs_PerStrip_Range: [number,number][] = [];
98
+ for (let i=0; i<ROW_COUNT; i++) {
99
+ const strip = strips[i];
100
+ const { lineSegs } = strip;
101
+
102
+ //////////
103
+ const L = lineSegs.length;
104
+ segIdxs_PerStrip_Range.push([S3, L]);
105
+ S3 += L;
106
+ allSegs.push(...lineSegs);
107
+ }
108
+
109
+
110
+ // all line segments, with their ranges per cell and per strip
111
+ const lineSegPtCoords_Arr = new Float32Array(allSegs.flat(2));
112
+ const segIdxs_PerCell_Range_Arr = new Int32Array(segIdxs_PerCell_Range.flat());
113
+
114
+ // close cell idxs and range
115
+ const closeCellIdxs_PerCell_Range_Arr = new Int32Array(closeCellIdxs_PerCell_Range.flat());
116
+ const closeCellIdxs_PerCell_Arr = new Int32Array(closeCellIdxs_PerCell);
117
+
118
+ // cross cell idxs and range
119
+ const crossCellIdxs_PerCell_Arr = new Int32Array(crossCellIdxs_PerCell);
120
+ const crossCellIdxs_perCell_Range_Arr = new Int32Array(crossCellIdxs_PerCell_Range.flat());
121
+
122
+ // segment index ranges per strip
123
+ const segIdxs_PerStrip_Range_Arr = new Int32Array(segIdxs_PerStrip_Range.flat());
124
+
125
+ // testing
126
+ // const r = sum(closeCellIdxsPerCell_.map((c: number[]) => {
127
+ // let tot = 0;
128
+ // for (let i=0; i<c.length; i++) {
129
+ // const idx = c[i];
130
+ // const u = Math.trunc(idx / (ROW_COUNT + 2*padCount));
131
+ // const v = idx % (ROW_COUNT + 2*padCount);
132
+
133
+ // tot += grid[u][v].lineSegs.length;
134
+ // }
135
+ // return tot;
136
+ // }));
137
+ // console.log(r, r/colCount/ROW_COUNT);
138
+
139
+ return {
140
+ lineSegPtCoords_Arr,
141
+ segIdxs_PerCell_Range_Arr,
142
+ closeCellIdxs_PerCell_Arr, closeCellIdxs_PerCell_Range_Arr,
143
+ crossCellIdxs_PerCell_Arr, crossCellIdxs_perCell_Range_Arr,
144
+ segIdxs_PerStrip_Range_Arr
145
+ }
146
+ }
147
+
148
+
149
+ export { prepareBuffers }
@@ -0,0 +1,6 @@
1
+
2
+ // 32 works by far the best (empirically determined) as compared to e.g. 16 or 64
3
+ const ROW_COUNT = 32;
4
+
5
+
6
+ export { ROW_COUNT }
@@ -0,0 +1,157 @@
1
+ import { ROW_COUNT } from "../row-count"
2
+
3
+
4
+ const cache: { [padCount_times_colCount: number]: string } = {};
5
+
6
+
7
+ function getMainFragment(
8
+ colCount: number,
9
+ padCount: number): string {
10
+
11
+ const fragment = cache[1024*colCount + padCount];
12
+ if (fragment !== undefined) { return fragment; }
13
+
14
+ const main_Fragment =
15
+ /*glsl*/`#version 300 es
16
+
17
+ precision highp float;
18
+
19
+ uniform float uMaxDistance;
20
+ uniform float uExponent;
21
+ uniform highp sampler2D uSegs;
22
+ uniform highp isampler2D uCloseCellIdxs;
23
+ uniform highp isampler2D uCrossCellIdxs;
24
+ uniform int uIncl; // bit 0 -> incl inside, bit 1 -> incl outside
25
+
26
+ uniform SegIdxRangePerCellBlock {
27
+ ivec4 uSegIdxRangePerCell[${(ROW_COUNT + 2*padCount)*(colCount + 2*padCount) / 2}];
28
+ };
29
+ uniform SegIdxRangePerStripBlock {
30
+ ivec4 uSegIdxRangePerStrip[${ROW_COUNT / 2}];
31
+ };
32
+
33
+ in vec2 vXY;
34
+ flat in int instanceId;
35
+ flat in ivec2 closeCellIdxRange;
36
+ flat in ivec2 crossCellIdxRange;
37
+ out vec4 FragColor;
38
+
39
+
40
+ float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
41
+ vec2 lineDir = lineB - lineA;
42
+ float lenSq = dot(lineDir, lineDir);
43
+ float t = clamp(dot(point - lineA, lineDir) / lenSq, 0.0, 1.0);
44
+ vec2 linePt = lineA + t * lineDir;
45
+
46
+ return distance(point, linePt);
47
+ }
48
+
49
+
50
+ void main() {
51
+ ///////////////////////////////////////////////////////////////////////////
52
+ // Project a ray to the left to check if it crosses the segment in order
53
+ // to find the fragment's winding number to determine whether fragment
54
+ // is inside or outside the shape.
55
+
56
+ int crossIdxS = crossCellIdxRange.x;
57
+ int crossLen = crossCellIdxRange.y;
58
+ float winds = 0.0;
59
+ // Iterate over all relevant cell indexes
60
+ for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
61
+ int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
62
+
63
+ bool isEven = crossIdx % 2 == 0;
64
+
65
+ ivec4 uSegIdxRange = uSegIdxRangePerCell[crossIdx / 2];
66
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
67
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
68
+
69
+ for (int j = segIdx; j < segIdx + segLen; j++) {
70
+ // Fetch segment from texture
71
+ vec4 seg = texelFetch(uSegs, ivec2(j, 0), 0);
72
+
73
+ // line segment's min-y is excluded
74
+ bool crossing =
75
+ (seg.y > vXY.y != seg.w > vXY.y) &&
76
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
77
+
78
+ bool crossingUp = seg.y < seg.w;
79
+
80
+ winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
81
+ }
82
+ }
83
+
84
+ {
85
+ bool isEven = (instanceId % ${ROW_COUNT}) % 2 == 0;
86
+
87
+ ivec4 uSegIdxRange = uSegIdxRangePerStrip[(instanceId % ${ROW_COUNT}) / 2];
88
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
89
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
90
+
91
+ for (int j = segIdx; j < segIdx + segLen; j++) {
92
+ // Fetch segment from texture
93
+ vec4 seg = texelFetch(uSegs, ivec2(j, 0), 0);
94
+
95
+ // line segment's min-y is excluded
96
+ bool crossing =
97
+ (seg.y > vXY.y != seg.w > vXY.y) &&
98
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
99
+
100
+ bool crossingUp = seg.y < seg.w;
101
+
102
+ winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
103
+ }
104
+ }
105
+
106
+
107
+ bool inside = winds != 0.0;
108
+ ///////////////////////////////////////////////////////////////////////////
109
+
110
+ ///////////////////////////////////////////////////////////////////////////
111
+ float res = 1.0; // sdf result
112
+
113
+ if ((inside && (uIncl % 2 != 0)) || (!inside && (uIncl > 1))) {
114
+ int cellIdxS = closeCellIdxRange.x;
115
+ int cellLen = closeCellIdxRange.y;
116
+ // Iterate over all relevant cell indexes
117
+ for (int i = cellIdxS; i < cellIdxS + cellLen; i++) {
118
+ int cellIdx = texelFetch(uCloseCellIdxs, ivec2(i%256, i/256), 0).x;
119
+
120
+ bool isEven = cellIdx % 2 == 0;
121
+ ivec4 uSegIdxRange = uSegIdxRangePerCell[cellIdx / 2];
122
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
123
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
124
+
125
+ for (int j = segIdx; j < segIdx + segLen; j++) {
126
+ // Fetch segment from texture
127
+ vec4 seg = texelFetch(uSegs, ivec2(j, 0), 0);
128
+
129
+ // Find unsigned distance to the segment; only the nearest will be kept
130
+ float d = absDistToSegment(vXY, seg.xy, seg.zw);
131
+ // Apply exponential transform TODO
132
+ // val = pow(1.0 - clamp(d / uMaxDistance, 0.0, 1.0), uExponent) * 0.5;
133
+ float val = clamp(d / uMaxDistance, 0.0, 1.0);
134
+ res = min(res, val);
135
+ }
136
+ }
137
+ }
138
+ ///////////////////////////////////////////////////////////////////////////
139
+
140
+ // DEBUG!
141
+ float alpha = ((instanceId + instanceId/${ROW_COUNT}) % 2 == 0 ? 0.3 : 0.5);
142
+
143
+ float red = inside ? 0.2 : 0.8;
144
+ float green = abs(sin(50.0 * res));
145
+ float blue = 0.5;
146
+ // float alpha = inside ? 0.5 : 0.0;
147
+
148
+ FragColor = vec4(red, green, blue, alpha);
149
+ }
150
+ `
151
+
152
+ cache[1024*colCount + padCount] = main_Fragment;
153
+ return main_Fragment;
154
+ }
155
+
156
+
157
+ export { getMainFragment }
@@ -0,0 +1,55 @@
1
+ import { ROW_COUNT } from "../row-count";
2
+
3
+ const main_Vertex = /*glsl*/`#version 300 es
4
+
5
+ precision highp float;
6
+
7
+ uniform vec2 uWidthHeight;
8
+ uniform float uStretch;
9
+ in vec2 aUV;
10
+ in ivec2 aCloseCellIdxRangePerCell;
11
+ in ivec2 aCrossIdxRangePerCell;
12
+ out vec2 vXY;
13
+ flat out int instanceId;
14
+ flat out ivec2 closeCellIdxRange;
15
+ flat out ivec2 crossCellIdxRange;
16
+
17
+
18
+ void main() {
19
+ instanceId = gl_InstanceID;
20
+ closeCellIdxRange = aCloseCellIdxRangePerCell;
21
+ crossCellIdxRange = aCrossIdxRangePerCell;
22
+
23
+ // drawn column-by-column
24
+ float i = float(instanceId / ${ROW_COUNT}); // column index
25
+ float j = float(instanceId % ${ROW_COUNT}); // row index
26
+
27
+ vec2 trans = vec2(
28
+ i / float(${ROW_COUNT}),
29
+ j / float(${ROW_COUNT})
30
+ );
31
+
32
+ vec2 uv = aUV + trans;
33
+
34
+ float width = uWidthHeight.x;
35
+ float height = uWidthHeight.y;
36
+
37
+ vXY = vec2(
38
+ height * uv.x,
39
+ height * uv.y
40
+ );
41
+
42
+ float aspectRatio = width / height;
43
+
44
+ gl_Position = vec4(
45
+ vec2(
46
+ (2.0*(uv.x / aspectRatio) - 1.0),
47
+ 2.0*uv.y - 1.0
48
+ ),
49
+ 0.0, 1.0
50
+ );
51
+ }
52
+ `;
53
+
54
+
55
+ export { main_Vertex }