|
|
|
@ -102,18 +102,17 @@ const nop_fs_src = `#version 300 es
@@ -102,18 +102,17 @@ const nop_fs_src = `#version 300 es
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const sdf_vs_src = `#version 300 es
|
|
|
|
|
in vec3 a_pos; // .z is radius
|
|
|
|
|
in vec4 a_line; |
|
|
|
|
in vec3 a_color; |
|
|
|
|
|
|
|
|
|
in vec4 a_ab; // original points
|
|
|
|
|
in float a_radius; |
|
|
|
|
in int a_stroke_id; |
|
|
|
|
|
|
|
|
|
uniform vec2 u_scale; |
|
|
|
|
uniform vec2 u_res; |
|
|
|
|
uniform vec2 u_translation; |
|
|
|
|
|
|
|
|
|
uniform int u_stroke_count; |
|
|
|
|
|
|
|
|
|
uniform highp sampler2D u_stroke_data; |
|
|
|
|
|
|
|
|
|
out vec4 v_line; |
|
|
|
|
out vec2 v_texcoord; |
|
|
|
|
out vec3 v_color; |
|
|
|
@ -121,40 +120,52 @@ const sdf_vs_src = `#version 300 es
@@ -121,40 +120,52 @@ const sdf_vs_src = `#version 300 es
|
|
|
|
|
flat out float v_thickness; |
|
|
|
|
|
|
|
|
|
void main() { |
|
|
|
|
vec2 screen01 = (a_pos.xy * u_scale + u_translation) / u_res; |
|
|
|
|
vec2 screen02 = screen01 * 2.0; |
|
|
|
|
|
|
|
|
|
float apron = 2.0; |
|
|
|
|
vec2 line_dir = normalize(a_line.zw - a_line.xy); |
|
|
|
|
vec2 screen02; |
|
|
|
|
float apron = 1.0; // google "futanari inflation rule 34"
|
|
|
|
|
|
|
|
|
|
vec4 stroke_data = texelFetch(u_stroke_data, ivec2(a_stroke_id, 0), 0); |
|
|
|
|
float radius = stroke_data.w * 255.0; |
|
|
|
|
|
|
|
|
|
vec2 a = a_ab.xy; |
|
|
|
|
vec2 b = a_ab.zw; |
|
|
|
|
|
|
|
|
|
vec2 line_dir = normalize(b - a); |
|
|
|
|
vec2 up_dir = vec2(line_dir.y, -line_dir.x); |
|
|
|
|
vec2 pixel = vec2(2.0) / u_res * apron; |
|
|
|
|
float rscale = apron / u_scale.x; |
|
|
|
|
|
|
|
|
|
int vertex_index = gl_VertexID & 0x3; |
|
|
|
|
int vertex_index = gl_VertexID % 6; |
|
|
|
|
|
|
|
|
|
vec2 outwards; |
|
|
|
|
vec2 origin; |
|
|
|
|
|
|
|
|
|
if (vertex_index == 0) { |
|
|
|
|
// "top left" aka "p1"
|
|
|
|
|
screen02 += up_dir * pixel - line_dir * pixel; |
|
|
|
|
v_texcoord = a_pos.xy + up_dir * rscale - line_dir * rscale; |
|
|
|
|
} else if (vertex_index == 1) { |
|
|
|
|
origin = a; |
|
|
|
|
outwards = up_dir - line_dir; |
|
|
|
|
} else if (vertex_index == 1 || vertex_index == 5) { |
|
|
|
|
// "top right" aka "p2"
|
|
|
|
|
screen02 += up_dir * pixel + line_dir * pixel; |
|
|
|
|
v_texcoord = a_pos.xy + up_dir * rscale + line_dir * rscale; |
|
|
|
|
} else if (vertex_index == 2) { |
|
|
|
|
origin = b; |
|
|
|
|
outwards = up_dir + line_dir; |
|
|
|
|
} else if (vertex_index == 2 || vertex_index == 4) { |
|
|
|
|
// "bottom left" aka "p3"
|
|
|
|
|
screen02 += -up_dir * pixel - line_dir * pixel; |
|
|
|
|
v_texcoord = a_pos.xy - up_dir * rscale - line_dir * rscale; |
|
|
|
|
origin = a; |
|
|
|
|
outwards = -up_dir - line_dir; |
|
|
|
|
} else { |
|
|
|
|
// "bottom right" aka "p4"
|
|
|
|
|
screen02 += -up_dir * pixel + line_dir * pixel; |
|
|
|
|
v_texcoord = a_pos.xy - up_dir * rscale + line_dir * rscale; |
|
|
|
|
origin = b; |
|
|
|
|
outwards = -up_dir + line_dir; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vec2 pos = origin + normalize(outwards) * radius; |
|
|
|
|
screen02 = (pos.xy * u_scale + u_translation) / u_res + outwards * pixel; |
|
|
|
|
v_texcoord = pos.xy + outwards * rscale; |
|
|
|
|
|
|
|
|
|
screen02.y = 2.0 - screen02.y; |
|
|
|
|
|
|
|
|
|
v_line = a_line; |
|
|
|
|
v_color = a_color; |
|
|
|
|
v_thickness = a_pos.z; |
|
|
|
|
v_line = vec4(a, b); |
|
|
|
|
v_thickness = radius; |
|
|
|
|
v_color = stroke_data.xyz; |
|
|
|
|
|
|
|
|
|
gl_Position = vec4(screen02 - 1.0, (float(a_stroke_id) / float(u_stroke_count)) * 2.0 - 1.0, 1); |
|
|
|
|
} |
|
|
|
@ -182,8 +193,8 @@ const sdf_fs_src = `#version 300 es
@@ -182,8 +193,8 @@ const sdf_fs_src = `#version 300 es
|
|
|
|
|
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); |
|
|
|
|
float dist = length(pa - ba * h) - v_thickness / 2.0; |
|
|
|
|
|
|
|
|
|
float fade = length(fwidth(v_texcoord)); |
|
|
|
|
float alpha = 1.0 - smoothstep(0.0, fade, dist); |
|
|
|
|
float fade = 0.5 * length(fwidth(v_texcoord)); |
|
|
|
|
float alpha = 1.0 - smoothstep(-fade, fade, dist); |
|
|
|
|
|
|
|
|
|
FragColor = vec4(v_color * alpha, alpha); |
|
|
|
|
} else { |
|
|
|
@ -292,17 +303,15 @@ function init_webgl(state, context) {
@@ -292,17 +303,15 @@ function init_webgl(state, context) {
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
'main': { |
|
|
|
|
'a_pos': gl.getAttribLocation(context.programs['sdf'].main, 'a_pos'), |
|
|
|
|
'a_line': gl.getAttribLocation(context.programs['sdf'].main, 'a_line'), |
|
|
|
|
'a_color': gl.getAttribLocation(context.programs['sdf'].main, 'a_color'), |
|
|
|
|
'a_ab': gl.getAttribLocation(context.programs['sdf'].main, 'a_ab'), |
|
|
|
|
'a_stroke_id': gl.getAttribLocation(context.programs['sdf'].main, 'a_stroke_id'), |
|
|
|
|
|
|
|
|
|
'u_res': gl.getUniformLocation(context.programs['sdf'].main, 'u_res'), |
|
|
|
|
'u_scale': gl.getUniformLocation(context.programs['sdf'].main, 'u_scale'), |
|
|
|
|
'u_translation': gl.getUniformLocation(context.programs['sdf'].main, 'u_translation'), |
|
|
|
|
'u_debug_mode': gl.getUniformLocation(context.programs['sdf'].main, 'u_debug_mode'), |
|
|
|
|
'u_tile_size': gl.getUniformLocation(context.programs['sdf'].main, 'u_tile_size'), |
|
|
|
|
'u_stroke_count': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_count'), |
|
|
|
|
'u_stroke_data': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_data'), |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -321,6 +330,15 @@ function init_webgl(state, context) {
@@ -321,6 +330,15 @@ function init_webgl(state, context) {
|
|
|
|
|
'b_packed_dynamic_index': gl.createBuffer(), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
context.textures = { |
|
|
|
|
'stroke_data': gl.createTexture(), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']); |
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); |
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); |
|
|
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
|
|
|
|
|
|
|
|
|
const resize_canvas = (entries) => { |
|
|
|
|
// https://www.khronos.org/webgl/wiki/HandlingHighDPI
|
|
|
|
|
const entry = entries[0]; |
|
|
|
|