webgl2-sdf 0.0.7 → 0.0.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.
@@ -4,11 +4,38 @@ import { ROW_COUNT } from "../row-count.js";
4
4
  const cache: { [padCount_times_colCount: number]: string } = {};
5
5
 
6
6
 
7
+ const GLSL_PATTERN1 = `
8
+ float exponent = uCustom.x;
9
+ float alpha = res >= 1.0 ? 0.0 : 0.5;
10
+ res = pow(1.0 - res, exponent);
11
+ float red = inside ? 0.2 : 0.8;
12
+ float green = abs(sin(25.0 * res));
13
+ // float green = step(0.5, fract(10.0 * res));
14
+ float blue = 0.5;
15
+ `;
16
+
17
+
18
+ const GLSL_DEFAULT = `
19
+ float exponent = uCustom.x;
20
+ float adj = 0.5*pow(1.0 - res, exponent);
21
+ res = inside ? 1.0 - adj : adj;
22
+ float red = res;
23
+ float green = res;
24
+ float blue = res;
25
+ float alpha = res;
26
+ `;
27
+
28
+
7
29
  function getFragment(
8
30
  colCount: number,
9
- padCount: number): string {
10
-
11
- const fragment = cache[1024*colCount + padCount];
31
+ padCount: number,
32
+ calcFragColorStr: string,
33
+ hash: number): string {
34
+
35
+ // `colCount` and `padCount` can take at most 8 bits and `has` 32 bits and
36
+ // we have at least 53 bits to play with so we're fine
37
+ const key = (2**32)*(256*colCount + padCount) + hash;
38
+ const fragment = cache[key];
12
39
  if (fragment !== undefined) { return fragment; }
13
40
 
14
41
  const main_Fragment =
@@ -20,7 +47,11 @@ uniform float uMaxDistance;
20
47
  uniform highp sampler2D uSegs;
21
48
  uniform highp isampler2D uCloseCellIdxs;
22
49
  uniform highp isampler2D uCrossCellIdxs;
23
- uniform int uIncl; // bit 0 -> incl inside, bit 1 -> incl outside
50
+ // bit 0 -> calc distance inside
51
+ // bit 1 -> calc distance outside
52
+ // bit 2 -> calc whether fragment is inside or outside (else outside is assumed with winds == 0.0)
53
+ uniform int uTestInOut;
54
+ uniform vec4 uCustom;
24
55
 
25
56
  uniform SegIdxRangePerCellBlock {
26
57
  ivec4 uSegIdxRangePerCell[${(ROW_COUNT + 2*padCount)*(colCount + 2*padCount) / 2}];
@@ -35,6 +66,10 @@ flat in ivec2 closeCellIdxRange;
35
66
  flat in ivec2 crossCellIdxRange;
36
67
  out vec4 FragColor;
37
68
 
69
+ // testing!!
70
+ // float rand(vec2 co) {
71
+ // return mod(uCustom.w * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453), 1.0);
72
+ // }
38
73
 
39
74
  float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
40
75
  vec2 lineDir = lineB - lineA;
@@ -48,72 +83,75 @@ float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
48
83
 
49
84
  void main() {
50
85
  ///////////////////////////////////////////////////////////////////////////
86
+ // Calculate \`winds\`:
87
+ //
51
88
  // Project a ray to the left to check if it crosses the segment in order
52
89
  // to find the fragment's winding number to determine whether fragment
53
90
  // is inside or outside the shape.
91
+ ///////////////////////////////////////////////////////////////////////////
54
92
 
55
- int crossIdxS = crossCellIdxRange.x;
56
- int crossLen = crossCellIdxRange.y;
57
93
  float winds = 0.0;
58
- // Iterate over all relevant cell indexes
59
- for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
60
- int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
94
+ if ((uTestInOut & 4) != 0) {
95
+ int crossIdxS = crossCellIdxRange.x;
96
+ int crossLen = crossCellIdxRange.y;
97
+ // Iterate over all relevant cell indexes
98
+ for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
99
+ int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
61
100
 
62
- ivec2 uSegIdxRange = crossIdx % 2 == 0
63
- ? uSegIdxRangePerCell[crossIdx / 2].xy
64
- : uSegIdxRangePerCell[crossIdx / 2].zw;
101
+ ivec2 uSegIdxRange = crossIdx % 2 == 0
102
+ ? uSegIdxRangePerCell[crossIdx / 2].xy
103
+ : uSegIdxRangePerCell[crossIdx / 2].zw;
65
104
 
66
- int segIdx = uSegIdxRange.x;
67
- int segLen = uSegIdxRange.y;
105
+ int segIdx = uSegIdxRange.x;
106
+ int segLen = uSegIdxRange.y;
68
107
 
69
- for (int j = segIdx; j < segIdx + segLen; j++) {
70
- // Fetch segment from texture
71
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
108
+ for (int j = segIdx; j < segIdx + segLen; j++) {
109
+ // Fetch segment from texture
110
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
72
111
 
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);
112
+ // line segment's min-y is excluded
113
+ bool crossing =
114
+ (seg.y > vXY.y != seg.w > vXY.y) &&
115
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
77
116
 
78
- bool crossingUp = seg.y < seg.w;
117
+ bool crossingUp = seg.y < seg.w;
79
118
 
80
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
119
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
120
+ }
81
121
  }
82
- }
83
122
 
84
- {
85
- int cellIdx = (instanceId % ${ROW_COUNT});
123
+ {
124
+ int cellIdx = (instanceId % ${ROW_COUNT});
86
125
 
87
- bool isEven = cellIdx % 2 == 0;
126
+ bool isEven = cellIdx % 2 == 0;
88
127
 
89
- ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
90
- int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
91
- int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
92
-
128
+ ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
129
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
130
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
131
+
93
132
 
94
- for (int j = segIdx; j < segIdx + segLen; j++) {
95
- // Fetch segment from texture
96
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
133
+ for (int j = segIdx; j < segIdx + segLen; j++) {
134
+ // Fetch segment from texture
135
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
97
136
 
98
- // line segment's min-y is excluded
99
- bool crossing =
100
- (seg.y > vXY.y != seg.w > vXY.y) &&
101
- (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
137
+ // line segment's min-y is excluded
138
+ bool crossing =
139
+ (seg.y > vXY.y != seg.w > vXY.y) &&
140
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
102
141
 
103
- bool crossingUp = seg.y < seg.w;
142
+ bool crossingUp = seg.y < seg.w;
104
143
 
105
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
144
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
145
+ }
106
146
  }
107
147
  }
108
-
109
-
110
148
  bool inside = winds != 0.0;
111
149
  ///////////////////////////////////////////////////////////////////////////
112
-
150
+ // Calculate \`res\`: the distance to the nearest curve
113
151
  ///////////////////////////////////////////////////////////////////////////
114
152
  float res = 1.0; // sdf result
115
153
 
116
- if ((inside && (uIncl % 2 != 0)) || (!inside && (uIncl > 1))) {
154
+ if ((inside && ((uTestInOut & 1) != 0)) || (!inside && ((uTestInOut & 2) != 0))) {
117
155
  int cellIdxS = closeCellIdxRange.x;
118
156
  int cellLen = closeCellIdxRange.y;
119
157
  // Iterate over all relevant cell indexes
@@ -131,9 +169,8 @@ void main() {
131
169
  // Fetch segment from texture
132
170
  vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
133
171
 
134
- // Find unsigned distance to the segment; only the nearest will be kept
172
+ // Find normalized unsigned distance to the segment; only the nearest will be kept
135
173
  float d = absDistToSegment(vXY, seg.xy, seg.zw);
136
- // Apply exponential transform
137
174
  float val = clamp(d / uMaxDistance, 0.0, 1.0);
138
175
 
139
176
  res = min(res, val);
@@ -145,22 +182,16 @@ void main() {
145
182
  // DEBUG!
146
183
  // float alpha = ((instanceId + instanceId/${ROW_COUNT}) % 2 == 0 ? 0.3 : 0.5);
147
184
 
148
-
149
- float exponent = 2;
150
- res = pow(1.0 - val, exponent) * 0.5;
151
-
152
- float alpha = res == 1.0 ? 0.0 : 0.5;
153
- float red = inside ? 0.2 : 0.8;
154
- float green = abs(sin(25.0 * res));
155
- float blue = 0.5;
185
+
186
+ ${calcFragColorStr}
156
187
 
157
188
  FragColor = vec4(red, green, blue, alpha);
158
189
  }
159
190
  `
160
191
 
161
- cache[1024*colCount + padCount] = main_Fragment;
192
+ cache[key] = main_Fragment;
162
193
  return main_Fragment;
163
194
  }
164
195
 
165
196
 
166
- export { getFragment }
197
+ export { getFragment, GLSL_PATTERN1, GLSL_DEFAULT }
@@ -8,13 +8,8 @@ import type { Texture } from "./texture";
8
8
  *
9
9
  * * `textures`
10
10
  * * `programs`
11
- * * `framebufferStack`
12
11
  *
13
12
  * so they don't have to be recreated on each draw call.
14
- *
15
- * * an optional `width` and `height` that can be used for any purpose and that are not
16
- * set or read by any function within the library
17
- *
18
13
  */
19
14
  interface GlContext {
20
15
  readonly gl: WebGL2RenderingContext;
@@ -1,6 +1,7 @@
1
1
  import type { Texture } from "../types/texture.js";
2
2
  import type { Program } from "../types/program.js";
3
3
  import type { GlContext } from "../types/gl-context.js";
4
+ import { debugShaders } from "../debug-shaders.js";
4
5
 
5
6
 
6
7
  const cache = new WeakMap<WebGL2RenderingContext, GlContext>();
@@ -21,6 +22,8 @@ function getWebGlContext(
21
22
  if (glContext) { return glContext; }
22
23
  }
23
24
 
25
+ debugShaders(gl);
26
+
24
27
  const programs: { [index:string]: Program } = {};
25
28
  const textures: { [index:string]: Texture } = {};
26
29