|  |  |  | @ -13,22 +13,19 @@ const sdf_vs_src = `#version 300 es@@ -13,22 +13,19 @@ const sdf_vs_src = `#version 300 es | 
			
		
	
		
			
				
					|  |  |  |  |     uniform highp usampler2D u_stroke_data; | 
			
		
	
		
			
				
					|  |  |  |  |     uniform float u_fixed_pixel_width; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     out vec4 v_line; | 
			
		
	
		
			
				
					|  |  |  |  |     out vec2 v_texcoord; | 
			
		
	
		
			
				
					|  |  |  |  |     out vec3 v_color; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     flat out vec2 v_thickness; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     void main() { | 
			
		
	
		
			
				
					|  |  |  |  |         const float PI = 3.1415926; | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 screen02;  | 
			
		
	
		
			
				
					|  |  |  |  |         float apron = 1.0; // google "futanari inflation rule 34"
 | 
			
		
	
		
			
				
					|  |  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |  |         int stroke_data_y = a_stroke_id / u_stroke_texture_size; | 
			
		
	
		
			
				
					|  |  |  |  |         int stroke_data_x = a_stroke_id % u_stroke_texture_size; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 line_dir = normalize(a_b - a_a); | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 up_dir = vec2(line_dir.y, -line_dir.x); | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 pixel = vec2(2.0) / u_res; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         uvec4 stroke_data = texelFetch(u_stroke_data, ivec2(stroke_data_x, stroke_data_y), 0); | 
			
		
	
		
			
				
					|  |  |  |  |         float radius = float(stroke_data.w); | 
			
		
	
	
		
			
				
					|  |  |  | @ -37,40 +34,65 @@ const sdf_vs_src = `#version 300 es@@ -37,40 +34,65 @@ const sdf_vs_src = `#version 300 es | 
			
		
	
		
			
				
					|  |  |  |  |             radius = u_fixed_pixel_width / u_scale.x; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |  |         float rscale = apron / u_scale.x; | 
			
		
	
		
			
				
					|  |  |  |  |         int vertex_index = gl_VertexID % 6; | 
			
		
	
		
			
				
					|  |  |  |  |         int vertex_index = gl_VertexID % 198; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 outwards; | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 origin; | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 pos; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (vertex_index == 0) { | 
			
		
	
		
			
				
					|  |  |  |  |             // "top left" aka "p1"
 | 
			
		
	
		
			
				
					|  |  |  |  |             origin = a_a; | 
			
		
	
		
			
				
					|  |  |  |  |             outwards = up_dir - line_dir;  | 
			
		
	
		
			
				
					|  |  |  |  |         } else if (vertex_index == 1 || vertex_index == 5) { | 
			
		
	
		
			
				
					|  |  |  |  |             // "top right" aka "p2"
 | 
			
		
	
		
			
				
					|  |  |  |  |             origin = a_b; | 
			
		
	
		
			
				
					|  |  |  |  |             outwards = up_dir + line_dir; | 
			
		
	
		
			
				
					|  |  |  |  |         } else if (vertex_index == 2 || vertex_index == 4) { | 
			
		
	
		
			
				
					|  |  |  |  |             // "bottom left" aka "p3"
 | 
			
		
	
		
			
				
					|  |  |  |  |             origin = a_a; | 
			
		
	
		
			
				
					|  |  |  |  |             outwards = -up_dir - line_dir; | 
			
		
	
		
			
				
					|  |  |  |  |         if (vertex_index < 32 * 3) { | 
			
		
	
		
			
				
					|  |  |  |  |             // first cap
 | 
			
		
	
		
			
				
					|  |  |  |  |             float angle1 = float(vertex_index / 3) / 32.0 * PI * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             float angle2 = float((vertex_index + 1) / 3) / 32.0 * PI * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 dir1 = vec2(cos(angle1), sin(angle1)); | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 dir2 = vec2(cos(angle2), sin(angle2)); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if (vertex_index % 3 == 0) { | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a + dir1 * radius * a_pressure.x * 2.0;  | 
			
		
	
		
			
				
					|  |  |  |  |             } else if (vertex_index % 3 == 1) { | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a; | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a + dir2 * radius * a_pressure.x * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } else if (vertex_index < 102) { | 
			
		
	
		
			
				
					|  |  |  |  |             // connecting line
 | 
			
		
	
		
			
				
					|  |  |  |  |             if (vertex_index == 96) { | 
			
		
	
		
			
				
					|  |  |  |  |                 // top left
 | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a + up_dir * radius * a_pressure.x * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } else if (vertex_index == 97 || vertex_index == 101) { | 
			
		
	
		
			
				
					|  |  |  |  |                 // top right
 | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_b + up_dir * radius * a_pressure.y * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } else if (vertex_index == 98 || vertex_index == 100) { | 
			
		
	
		
			
				
					|  |  |  |  |                 // bottom left
 | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a - up_dir * radius * a_pressure.x * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 // bottom right
 | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_b - up_dir * radius * a_pressure.y * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             // second cap
 | 
			
		
	
		
			
				
					|  |  |  |  |             float angle1 = float((vertex_index - 102) / 3) / 32.0 * PI * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             float angle2 = float((vertex_index - 101) / 3) / 32.0 * PI * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 dir1 = vec2(cos(angle1), sin(angle1)); | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 dir2 = vec2(cos(angle2), sin(angle2)); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if ((vertex_index - 102) % 3 == 0) { | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_b + dir1 * radius * a_pressure.y * 2.0;  | 
			
		
	
		
			
				
					|  |  |  |  |             } else if ((vertex_index - 102) % 3 == 1) { | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_a; | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |             // "bottom right" aka "p4"
 | 
			
		
	
		
			
				
					|  |  |  |  |             origin = a_b; | 
			
		
	
		
			
				
					|  |  |  |  |             outwards = -up_dir + line_dir; | 
			
		
	
		
			
				
					|  |  |  |  |                 pos = a_b + dir2 * radius * a_pressure.y * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         vec2 pos = origin + normalize(outwards) * radius * 2.0 * max(a_pressure.x, a_pressure.y); // doubling is to account for max possible pressure
 | 
			
		
	
		
			
				
					|  |  |  |  |         screen02 = (pos.xy * u_scale + u_translation) / u_res * 2.0 + outwards * pixel * apron; | 
			
		
	
		
			
				
					|  |  |  |  |         v_texcoord = pos.xy + outwards * rscale; | 
			
		
	
		
			
				
					|  |  |  |  |         screen02 = (pos.xy * u_scale + u_translation) / u_res * 2.0; | 
			
		
	
		
			
				
					|  |  |  |  |         screen02.y = 2.0 - screen02.y; | 
			
		
	
		
			
				
					|  |  |  |  |         v_line = vec4(a_a, a_b);         | 
			
		
	
		
			
				
					|  |  |  |  |         v_thickness = radius * a_pressure; // pressure 0.5 is the "neutral" pressure
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         v_color = vec3(stroke_data.xyz) / 255.0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (a_stroke_id >> 31 != 0) { | 
			
		
	
		
			
				
					|  |  |  |  |             screen02 += vec2(100.0); // shift offscreen
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         gl_Position = vec4(screen02 - 1.0, (float(a_stroke_id) / float(u_stroke_count)) * 2.0 - 1.0, 1.0); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | `;
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -80,36 +102,13 @@ const sdf_fs_src = `#version 300 es@@ -80,36 +102,13 @@ const sdf_fs_src = `#version 300 es | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     uniform int u_debug_mode; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     in vec4 v_line; | 
			
		
	
		
			
				
					|  |  |  |  |     in vec2 v_texcoord; | 
			
		
	
		
			
				
					|  |  |  |  |     in vec3 v_color; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     flat in vec2 v_thickness; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     layout(location = 0) out vec4 FragColor; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     void main() { | 
			
		
	
		
			
				
					|  |  |  |  |         if (u_debug_mode == 0) { | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 a = v_line.xy; | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 b = v_line.zw; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             vec2 pa = v_texcoord - a.xy, ba = b.xy - a.xy; | 
			
		
	
		
			
				
					|  |  |  |  |             float dba = dot(ba, ba); | 
			
		
	
		
			
				
					|  |  |  |  |             float dist; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if (dba > 0.0) { | 
			
		
	
		
			
				
					|  |  |  |  |                 float h = clamp(dot(pa, ba) / dba, 0.0, 1.0); | 
			
		
	
		
			
				
					|  |  |  |  |                 dist = length(v_texcoord - (a + ba * h)) - mix(v_thickness.x, v_thickness.y, h); | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 // Special case for when we are drawing a single point. Just a circle SDF
 | 
			
		
	
		
			
				
					|  |  |  |  |                 dist = length(v_texcoord - a.xy - v_thickness.x); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             float fade = 0.5 * length(fwidth(v_texcoord)); | 
			
		
	
		
			
				
					|  |  |  |  |             float alpha = 1.0 - smoothstep(-fade, fade, dist); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             //if (alpha > 0.5) alpha = 0.5;
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             float alpha = 0.5; | 
			
		
	
		
			
				
					|  |  |  |  |             FragColor = vec4(v_color * alpha, alpha); | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             FragColor = vec4(0.2, 0.0, 0.0, 0.2); | 
			
		
	
	
		
			
				
					|  |  |  | @ -340,7 +339,7 @@ function init_webgl(state, context) {@@ -340,7 +339,7 @@ function init_webgl(state, context) { | 
			
		
	
		
			
				
					|  |  |  |  |     context.gl = context.canvas.getContext('webgl2', { | 
			
		
	
		
			
				
					|  |  |  |  |         'preserveDrawingBuffer': true, | 
			
		
	
		
			
				
					|  |  |  |  |         'desynchronized': true, | 
			
		
	
		
			
				
					|  |  |  |  |         'antialias': false, | 
			
		
	
		
			
				
					|  |  |  |  |         'antialias': true, | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     const gl = context.gl; | 
			
		
	
	
		
			
				
					|  |  |  | @ -349,8 +348,8 @@ function init_webgl(state, context) {@@ -349,8 +348,8 @@ function init_webgl(state, context) { | 
			
		
	
		
			
				
					|  |  |  |  |     gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); | 
			
		
	
		
			
				
					|  |  |  |  |     //gl.blendEquation(gl.MAX);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     //gl.enable(gl.DEPTH_TEST);
 | 
			
		
	
		
			
				
					|  |  |  |  |     //gl.depthFunc(gl.GEQUAL);
 | 
			
		
	
		
			
				
					|  |  |  |  |     gl.enable(gl.DEPTH_TEST); | 
			
		
	
		
			
				
					|  |  |  |  |     gl.depthFunc(gl.NOTEQUAL); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     context.gpu_timer_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2'); | 
			
		
	
		
			
				
					|  |  |  |  |     if (context.gpu_timer_ext === null) { | 
			
		
	
	
		
			
				
					|  |  |  | 
 |