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.
- package/README.md +100 -0
- package/node/bezier/bezier-curves-to-line-segs.d.ts +10 -0
- package/node/bezier/eval-de-casteljau.d.ts +17 -0
- package/node/bezier/from-to/from-to-2.d.ts +12 -0
- package/node/bezier/from-to/from-to-3.d.ts +12 -0
- package/node/bezier/from-to/from-to.d.ts +10 -0
- package/node/bezier/is-cubic-obtuse.d.ts +11 -0
- package/node/bezier/is-quad-obtuse.d.ts +11 -0
- package/node/bezier/is-really-point.d.ts +9 -0
- package/node/bezier/split-by-deviation-from-straight-line-cubic.d.ts +20 -0
- package/node/bezier/split-by-deviation-from-straight-line-quad.d.ts +11 -0
- package/node/bezier/split-into-line-segments.d.ts +10 -0
- package/node/debug-shaders.d.ts +9 -0
- package/node/generate-sdf.d.ts +18 -0
- package/node/helpers/calc-circs.d.ts +11 -0
- package/node/helpers/clip-line-segment-to-grid.d.ts +14 -0
- package/node/helpers/clip-line-segment-to-strips.d.ts +13 -0
- package/node/helpers/create-empty-grid.d.ts +8 -0
- package/node/helpers/create-empty-strips.d.ts +7 -0
- package/node/helpers/distance-seg-to-p.d.ts +5 -0
- package/node/helpers/find-close-cells.d.ts +3 -0
- package/node/helpers/find-crossing-cells.d.ts +3 -0
- package/node/helpers/get-distance-to-line-function.d.ts +10 -0
- package/node/helpers/jump-idx.d.ts +2 -0
- package/node/helpers/map-to-viewbox.d.ts +2 -0
- package/node/helpers/seg-box-x.d.ts +10 -0
- package/node/helpers/seg-strip-x.d.ts +9 -0
- package/node/index.d.ts +1 -0
- package/node/main-program.d.ts +4 -0
- package/node/max-aspect-ratio-before-stretch.d.ts +2 -0
- package/node/prepare-buffers.d.ts +10 -0
- package/node/row-count.d.ts +2 -0
- package/node/shaders/main.fragment.d.ts +2 -0
- package/node/shaders/main.vertex.d.ts +2 -0
- package/node/svg/get-beziers-from-raw-paths.d.ts +12 -0
- package/node/svg/get-paths-from-str.d.ts +9 -0
- package/node/svg/path-data-polyfill/parse-number.d.ts +10 -0
- package/node/svg/path-data-polyfill/parse-path-data-string.d.ts +9 -0
- package/node/svg/path-data-polyfill/source.d.ts +19 -0
- package/node/svg/path-segment/c.d.ts +19 -0
- package/node/svg/path-segment/h.d.ts +15 -0
- package/node/svg/path-segment/l.d.ts +16 -0
- package/node/svg/path-segment/q.d.ts +16 -0
- package/node/svg/path-segment/s.d.ts +20 -0
- package/node/svg/path-segment/t.d.ts +18 -0
- package/node/svg/path-segment/v.d.ts +15 -0
- package/node/svg/path-segment/z.d.ts +13 -0
- package/node/svg/path-state.d.ts +11 -0
- package/node/tex-width.d.ts +11 -0
- package/node/types/attribute.d.ts +6 -0
- package/node/types/cell.d.ts +18 -0
- package/node/types/gl-context.d.ts +28 -0
- package/node/types/gl-type.d.ts +2 -0
- package/node/types/gl-usage.d.ts +2 -0
- package/node/types/program.d.ts +16 -0
- package/node/types/strip.d.ts +8 -0
- package/node/types/texture.d.ts +4 -0
- package/node/utils/calc-circs.d.ts +11 -0
- package/node/utils/clip-line-segment-to-grid.d.ts +14 -0
- package/node/utils/clip-line-segment-to-strips.d.ts +13 -0
- package/node/utils/create-empty-grid.d.ts +8 -0
- package/node/utils/create-empty-strips.d.ts +7 -0
- package/node/utils/distance-seg-to-p.d.ts +5 -0
- package/node/utils/find-close-cells.d.ts +3 -0
- package/node/utils/find-crossing-cells.d.ts +3 -0
- package/node/utils/get-distance-to-line-function.d.ts +10 -0
- package/node/utils/jump-idx.d.ts +2 -0
- package/node/utils/map-to-viewbox.d.ts +2 -0
- package/node/utils/seg-box-x.d.ts +10 -0
- package/node/utils/seg-strip-x.d.ts +9 -0
- package/node/vector/dot.d.ts +8 -0
- package/node/vector/from-to-vec.d.ts +8 -0
- package/node/vector/len.d.ts +6 -0
- package/node/webgl-utils/compile-shader.d.ts +2 -0
- package/node/webgl-utils/get-gl-context.d.ts +10 -0
- package/node/webgl-utils/set-attribute.d.ts +15 -0
- package/node/webgl-utils/set-uniform-block.d.ts +9 -0
- package/node/webgl-utils/set-uniform.d.ts +4 -0
- package/node/webgl-utils/uniform-block.d.ts +6 -0
- package/node/webgl-utils/uniform-type.d.ts +2 -0
- package/node/webgl-utils/use-program.d.ts +17 -0
- package/node/webgl-utils/use-texture.d.ts +9 -0
- package/node/webgl2.d.ts +2 -0
- package/package.json +56 -0
- package/src/bezier/bezier-curves-to-line-segs.ts +39 -0
- package/src/bezier/eval-de-casteljau.ts +78 -0
- package/src/bezier/from-to/from-to-2.ts +159 -0
- package/src/bezier/from-to/from-to-3.ts +176 -0
- package/src/bezier/from-to/from-to.ts +30 -0
- package/src/bezier/is-cubic-obtuse.ts +31 -0
- package/src/bezier/is-quad-obtuse.ts +26 -0
- package/src/bezier/is-really-point.ts +25 -0
- package/src/bezier/split-by-deviation-from-straight-line-cubic.ts +109 -0
- package/src/bezier/split-by-deviation-from-straight-line-quad.ts +66 -0
- package/src/bezier/split-into-line-segments.ts +39 -0
- package/src/debug-shaders.ts +38 -0
- package/src/generate-sdf.ts +91 -0
- package/src/index.ts +2 -0
- package/src/main-program.ts +160 -0
- package/src/max-aspect-ratio-before-stretch.ts +5 -0
- package/src/prepare-buffers.ts +149 -0
- package/src/row-count.ts +6 -0
- package/src/shaders/main.fragment.ts +157 -0
- package/src/shaders/main.vertex.ts +55 -0
- package/src/svg/get-beziers-from-raw-paths.ts +112 -0
- package/src/svg/get-paths-from-str.ts +19 -0
- package/src/svg/path-data-polyfill/parse-number.ts +138 -0
- package/src/svg/path-data-polyfill/parse-path-data-string.ts +26 -0
- package/src/svg/path-data-polyfill/source.ts +176 -0
- package/src/svg/path-segment/c.ts +34 -0
- package/src/svg/path-segment/h.ts +28 -0
- package/src/svg/path-segment/l.ts +30 -0
- package/src/svg/path-segment/q.ts +30 -0
- package/src/svg/path-segment/s.ts +40 -0
- package/src/svg/path-segment/t.ts +35 -0
- package/src/svg/path-segment/v.ts +28 -0
- package/src/svg/path-segment/z.ts +27 -0
- package/src/svg/path-state.ts +15 -0
- package/src/tex-width.ts +14 -0
- package/src/types/attribute.ts +9 -0
- package/src/types/cell.ts +21 -0
- package/src/types/gl-context.ts +28 -0
- package/src/types/gl-type.ts +16 -0
- package/src/types/gl-usage.ts +14 -0
- package/src/types/program.ts +14 -0
- package/src/types/strip.ts +11 -0
- package/src/types/texture.ts +7 -0
- package/src/types/typed-array.ts +16 -0
- package/src/utils/calc-circs.ts +129 -0
- package/src/utils/clip-line-segment-to-grid.ts +133 -0
- package/src/utils/clip-line-segment-to-strips.ts +196 -0
- package/src/utils/create-empty-grid.ts +32 -0
- package/src/utils/create-empty-strips.ts +21 -0
- package/src/utils/distance-seg-to-p.ts +50 -0
- package/src/utils/find-close-cells.ts +171 -0
- package/src/utils/find-crossing-cells.ts +40 -0
- package/src/utils/get-distance-to-line-function.ts +59 -0
- package/src/utils/is-point-in-box.ts +16 -0
- package/src/utils/jump-idx.ts +107 -0
- package/src/utils/map-to-viewbox.ts +41 -0
- package/src/utils/path.ts +137 -0
- package/src/utils/seg-box-x.ts +84 -0
- package/src/utils/seg-strip-x.ts +72 -0
- package/src/utils/sum.ts +13 -0
- package/src/vector/dot.ts +13 -0
- package/src/vector/from-to-vec.ts +13 -0
- package/src/vector/len.ts +11 -0
- package/src/webgl-utils/compile-shader.ts +15 -0
- package/src/webgl-utils/get-gl-context.ts +61 -0
- package/src/webgl-utils/set-attribute.ts +74 -0
- package/src/webgl-utils/set-uniform-block.ts +45 -0
- package/src/webgl-utils/set-uniform.ts +24 -0
- package/src/webgl-utils/uniform-block.ts +9 -0
- package/src/webgl-utils/uniform-type.ts +10 -0
- package/src/webgl-utils/use-program.ts +48 -0
- 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,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,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 }
|
package/src/row-count.ts
ADDED
|
@@ -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 }
|