diff --git a/client/tools.js b/client/tools.js index 1c85828..d0f00c6 100644 --- a/client/tools.js +++ b/client/tools.js @@ -48,7 +48,7 @@ function hide_stroke_preview() { function switch_stroke_width(e, state) { if (!state.online) return; - const value = e.target.value; + const value = parseInt(e.target.value); state.players[state.me].width = value; show_stroke_preview(state, value); diff --git a/client/webgl_draw.js b/client/webgl_draw.js index 9434f35..cf1908b 100644 --- a/client/webgl_draw.js +++ b/client/webgl_draw.js @@ -31,41 +31,43 @@ function draw(state, context) { gl.enableVertexAttribArray(locations['a_pos']); gl.enableVertexAttribArray(locations['a_color']); - gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 4 * 3, 0); - gl.vertexAttribPointer(locations['a_color'], 3, gl.UNSIGNED_BYTE, true, 4 * 3, 4 * 2); + gl.vertexAttribPointer(locations['a_pos'], 3, gl.FLOAT, false, 4 * 4, 0); + gl.vertexAttribPointer(locations['a_color'], 3, gl.UNSIGNED_BYTE, true, 4 * 4, 4 * 3); gl.activeTexture(gl.TEXTURE0 + 0); gl.bindTexture(gl.TEXTURE_2D, textures['points']); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - const npoints = context.point_serializer.offset / (4 * 2); - const nstrokes = context.quad_serializer.offset / (6 * 3 * 4); - - // TOOD: if points changed - if (true) { - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG32F, npoints, 1, 0, gl.RG, gl.FLOAT, new Float32Array(context.point_serializer.buffer, 0, context.point_serializer.offset / 4)); - } - - gl.activeTexture(gl.TEXTURE0 + 1); - gl.bindTexture(gl.TEXTURE_2D, textures['indices']); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - - // TOOD: if points changed - if (true) { - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG32UI, nstrokes, 1, 0, gl.RG_INTEGER, gl.UNSIGNED_INT, new Uint32Array(context.index_serializer.buffer, 0, context.index_serializer.offset / 4)); + const npoints = context.point_serializer.offset / (4 * 2); + const nstrokes = context.quad_serializer.offset / (6 * 4 * 4); + + if (npoints > 0) { + // TOOD: if points changed + if (true) { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG32F, npoints, 1, 0, gl.RG, gl.FLOAT, new Float32Array(context.point_serializer.buffer, 0, context.point_serializer.offset / 4)); + } + + gl.activeTexture(gl.TEXTURE0 + 1); + gl.bindTexture(gl.TEXTURE_2D, textures['indices']); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + // TOOD: if points changed + if (true) { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG32UI, nstrokes, 1, 0, gl.RG_INTEGER, gl.UNSIGNED_INT, new Uint32Array(context.index_serializer.buffer, 0, context.index_serializer.offset / 4)); + } + + gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom); + gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y); + gl.uniform1i(locations['u_texture_points'], 0); + gl.uniform1i(locations['u_texture_indices'], 1); + + gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.quad_serializer.buffer, 0, context.quad_serializer.offset), gl.STATIC_DRAW); + gl.drawArrays(gl.TRIANGLES, 0, nstrokes * 6); } - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); - gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom); - gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y); - gl.uniform1i(locations['u_texture_points'], 0); - gl.uniform1i(locations['u_texture_indices'], 1); - - gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.quad_serializer.buffer, 0, context.quad_serializer.offset), gl.STATIC_DRAW); - gl.drawArrays(gl.TRIANGLES, 0, nstrokes * 6); - // Images // locations = context.locations['image']; // buffers = context.buffers['image']; diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index 6da0866..1649989 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -3,23 +3,24 @@ function push_point_xy(s, x, y) { ser_f32(s, y); } -function push_point_xyrgb(s, x, y, r, g, b) { +function push_point_xyzrgb(s, x, y, z, r, g, b) { ser_f32(s, x); ser_f32(s, y); + ser_f32(s, z); ser_u8(s, r); ser_u8(s, g); ser_u8(s, b); ser_align(s, 4); } -function push_quad_xyrgb(s, p1x, p1y, p4x, p4y, r, g, b) { - push_point_xyrgb(s, p1x, p1y, r, g, b); - push_point_xyrgb(s, p4x, p1y, r, g, b); - push_point_xyrgb(s, p1x, p4y, r, g, b); +function push_quad_xyzrgb(s, p1x, p1y, p4x, p4y, z, r, g, b) { + push_point_xyzrgb(s, p1x, p1y, z, r, g, b); + push_point_xyzrgb(s, p4x, p1y, z, r, g, b); + push_point_xyzrgb(s, p1x, p4y, z, r, g, b); - push_point_xyrgb(s, p4x, p4y, r, g, b); - push_point_xyrgb(s, p1x, p4y, r, g, b); - push_point_xyrgb(s, p4x, p1y, r, g, b); + push_point_xyzrgb(s, p4x, p4y, z, r, g, b); + push_point_xyzrgb(s, p1x, p4y, z, r, g, b); + push_point_xyzrgb(s, p4x, p1y, z, r, g, b); } function push_stroke(context, stroke) { @@ -43,21 +44,21 @@ function push_stroke(context, stroke) { let min_x, min_y, max_x, max_y; - min_x = Math.floor(points[0].x); - max_x = Math.ceil(points[0].x); + min_x = Math.floor(points[0].x - stroke_width / 2); + max_x = Math.ceil(points[0].x + stroke_width / 2); - min_y = Math.floor(points[0].y); - max_y = Math.ceil(points[0].y); + min_y = Math.floor(points[0].y - stroke_width / 2); + max_y = Math.ceil(points[0].y + stroke_width / 2); for (const p of points) { - min_x = Math.min(min_x, Math.floor(p.x)); - min_y = Math.min(min_y, Math.floor(p.y)); - max_x = Math.max(max_x, Math.ceil(p.x)); - max_y = Math.max(max_y, Math.ceil(p.y)); + min_x = Math.min(min_x, Math.floor(p.x - stroke_width / 2)); + min_y = Math.min(min_y, Math.floor(p.y - stroke_width / 2)); + max_x = Math.max(max_x, Math.ceil(p.x + stroke_width / 2)); + max_y = Math.max(max_y, Math.ceil(p.y + stroke_width / 2)); push_point_xy(context.point_serializer, p.x, p.y); } - push_quad_xyrgb(context.quad_serializer, min_x, min_y, max_x, max_y, r, g, b); + push_quad_xyzrgb(context.quad_serializer, min_x, min_y, max_x, max_y, stroke_width / 2, r, g, b); } function geometry_prepare_stroke(state) { diff --git a/client/webgl_shaders.js b/client/webgl_shaders.js index 3937df7..40980d0 100644 --- a/client/webgl_shaders.js +++ b/client/webgl_shaders.js @@ -1,5 +1,5 @@ const sdf_vs_src = `#version 300 es - in vec2 a_pos; + in vec3 a_pos; in vec3 a_color; uniform vec2 u_scale; @@ -8,16 +8,19 @@ const sdf_vs_src = `#version 300 es out vec2 v_texcoord; out vec3 v_color; + + flat out float v_thickness; flat out int v_vertexid; void main() { - vec2 screen01 = (a_pos * u_scale + u_translation) / u_res; + vec2 screen01 = (a_pos.xy * u_scale + u_translation) / u_res; vec2 screen02 = screen01 * 2.0; screen02.y = 2.0 - screen02.y; - v_texcoord = a_pos + vec2(0.5); + v_texcoord = a_pos.xy; v_vertexid = gl_VertexID; v_color = a_color; + v_thickness = a_pos.z; gl_Position = vec4(screen02 - 1.0, 0, 1); } @@ -31,13 +34,14 @@ const sdf_fs_src = `#version 300 es in vec2 v_texcoord; in vec3 v_color; + + flat in float v_thickness; flat in int v_vertexid; out vec4 FragColor; void main() { float mindist = 99999.9; - float th = 5.0; uvec4 indices = texelFetch(u_texture_indices, ivec2(v_vertexid / 6, 0), 0); @@ -50,7 +54,7 @@ const sdf_fs_src = `#version 300 es vec2 pa = v_texcoord - a.xy, ba = b.xy - a.xy; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); - float dist = length(pa - ba * h) - th; + float dist = length(pa - ba * h) - v_thickness; mindist = min(mindist, dist); } @@ -58,7 +62,7 @@ const sdf_fs_src = `#version 300 es float fade = 0.5 * length(fwidth(v_texcoord)); float alpha = 1.0 - smoothstep(-fade, fade, mindist); - FragColor = vec4(v_color * alpha, 0.1 + alpha); + FragColor = vec4(v_color * alpha, alpha); // FragColor = vec4(v_color, 1.0); } `;