|
|
|
@ -12,23 +12,20 @@ const sdf_vs_src = `#version 300 es
@@ -12,23 +12,20 @@ const sdf_vs_src = `#version 300 es
|
|
|
|
|
uniform int u_stroke_texture_size; |
|
|
|
|
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 < 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
} else { |
|
|
|
|
// "bottom right" aka "p4"
|
|
|
|
|
origin = a_b; |
|
|
|
|
outwards = -up_dir + line_dir; |
|
|
|
|
// 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 { |
|
|
|
|
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) { |
|
|
|
|