Browse Source

Boudning boxes debug draw. Fix missing mipmap warning. Fix dynamic stroke not drawing on empty canvas

sdf
Aleksey Olokhtonov 2 months ago
parent
commit
0c21579694
  1. 7
      README.txt
  2. 6
      client/config.js
  3. 5
      client/speed.js
  4. 31
      client/webgl_draw.js
  5. 1
      client/webgl_geometry.js
  6. 4
      client/webgl_listeners.js
  7. 62
      client/webgl_shaders.js

7
README.txt

@ -11,6 +11,7 @@ Release:
+ Textured quads (pictures, code already written in older version + Textured quads (pictures, code already written in older version
+ Resize and move pictures (draw handles) + Resize and move pictures (draw handles)
- Z-prepass fringe bug (also, when do we enable the prepass?) - Z-prepass fringe bug (also, when do we enable the prepass?)
- Frame-independent lerp where applicable
+ Bugs + Bugs
+ GC stalls!!! + GC stalls!!!
+ Stroke previews get connected when drawn without panning on touch devices + Stroke previews get connected when drawn without panning on touch devices
@ -19,7 +20,9 @@ Release:
+ Undo history of moving and scaling images seems messed up + Undo history of moving and scaling images seems messed up
- Nothing get's drawn if we enable snapping and draw a curve where first and last point match - Nothing get's drawn if we enable snapping and draw a curve where first and last point match
- Weird clipping on HMH desk full zoomout after running "benchmark" - Weird clipping on HMH desk full zoomout after running "benchmark"
- Stuck in color picker mode when mouse leaves screen
- Debug - Debug
* Debug view for BVH
- Restore ability to limit event range - Restore ability to limit event range
* Listeners/events/multiplayer * Listeners/events/multiplayer
+ Fix multiplayer LUL + Fix multiplayer LUL
@ -78,6 +81,10 @@ Bonus:
+ Migrate old non-pressure desks + Migrate old non-pressure desks
- Check out e.pressure on touch devices - Check out e.pressure on touch devices
- Send pressure in PREDRAW event - Send pressure in PREDRAW event
- Stroke smoothing
https://github.com/xournalpp/xournalpp/issues/2320
https://www.digital-epigraphy.com/tutorials/the-most-useful-new-features-of-photoshop-cc-using-brush-stroke-smoothing-for-digital-inking
https://stackoverflow.com/questions/20618804/how-to-smooth-a-curve-for-a-dataset
- Curve modification - Curve modification
- Select curves (with a lasso?) - Select curves (with a lasso?)
- Move whole curve - Move whole curve

6
client/config.js

@ -8,7 +8,7 @@ const config = {
second_finger_timeout: 500, second_finger_timeout: 500,
buffer_first_touchmoves: 5, buffer_first_touchmoves: 5,
debug_print: false, debug_print: false,
draw_bvh: true, draw_bvh: false,
zoom_delta: 0.05, zoom_delta: 0.05,
min_zoom_level: -250, min_zoom_level: -250,
max_zoom_level: 100, max_zoom_level: 100,
@ -28,8 +28,8 @@ const config = {
pattern_fadeout_max: 0.75, pattern_fadeout_max: 0.75,
min_pressure: 50, min_pressure: 50,
benchmark: { benchmark: {
zoom_level: -75, zoom_level: -18,
offset: { x: 425, y: -1195 }, offset: { x: 654, y: 372 },
frames: 500, frames: 500,
}, },
}; };

5
client/speed.js

@ -175,9 +175,8 @@ async function do_lod(state, context) {
// Dynamic input data that should (by design) never be too big // Dynamic input data that should (by design) never be too big
mem.set(tv_bytes(context.clipped_indices), clipped_indices); mem.set(tv_bytes(context.clipped_indices), clipped_indices);
// TODO: this is a very naive and dumb way of distributing work. Better way // NOTE: this static partitioning scheme turned out to be "good enough" (i.e., trying
// would be to distrubute strokes based on total point count, so that // to allocate approximately the same amount of points per job wasn't any faster)
// each worker gets approximately the same amout of _points_
const indices_per_thread = Math.floor(context.clipped_indices.size / state.wasm.workers.length); const indices_per_thread = Math.floor(context.clipped_indices.size / state.wasm.workers.length);
const offsets = { const offsets = {
'coords_from': buffers['coords_from'].offset, 'coords_from': buffers['coords_from'].offset,

31
client/webgl_draw.js

@ -317,6 +317,7 @@ async function draw(state, context, animate, ts) {
// Dynamic strokes should be drawn above static strokes // Dynamic strokes should be drawn above static strokes
gl.clear(gl.DEPTH_BUFFER_BIT); gl.clear(gl.DEPTH_BUFFER_BIT);
gl.useProgram(pr.program);
gl.uniform1i(pr.locations['u_stroke_count'], dynamic_stroke_count); gl.uniform1i(pr.locations['u_stroke_count'], dynamic_stroke_count);
gl.uniform1i(pr.locations['u_stroke_data'], 0); gl.uniform1i(pr.locations['u_stroke_data'], 0);
@ -422,17 +423,43 @@ async function draw(state, context, animate, ts) {
} }
if (config.draw_bvh) { if (config.draw_bvh) {
const pr = programs['iquad'];
const bboxes = tv_create(Float32Array, context.clipped_indices.size * 4); const bboxes = tv_create(Float32Array, context.clipped_indices.size * 4);
// Debug BVH viz // Debug BVH viz
for (let i = 0; i < context.clipped_indices.size; ++i) { for (let i = 0; i < context.clipped_indices.size; ++i) {
const stroke_id = context.clipped_indices.data[i]; const stroke_id = context.clipped_indices.data[i];
const stroke = state.events[stroke_id]; const stroke = state.events[stroke_id];
const stroke_bbox = state.bvh.nodes[stroke.bvh_node].bbox;
tv_add(bboxes, stroke.bbox.x1); tv_add(bboxes, stroke.bbox.x1);
tv_add(bboxes, stroke.bbox.x2);
tv_add(bboxes, stroke.bbox.y1); tv_add(bboxes, stroke.bbox.y1);
tv_add(bboxes, stroke.bbox.x2);
tv_add(bboxes, stroke.bbox.y2); tv_add(bboxes, stroke.bbox.y2);
} }
const quad_count = bboxes.size / 4;
gl.useProgram(pr.program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_iquads']);
gl.bufferData(gl.ARRAY_BUFFER, tv_data(bboxes), gl.STREAM_DRAW);
gl.uniform2f(pr.locations['u_res'], context.canvas.width, context.canvas.height);
gl.uniform2f(pr.locations['u_scale'], state.canvas.zoom, state.canvas.zoom);
gl.uniform2f(pr.locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y);
gl.enableVertexAttribArray(pr.locations['a_topleft']);
gl.enableVertexAttribArray(pr.locations['a_bottomright']);
gl.vertexAttribPointer(pr.locations['a_topleft'], 2, gl.FLOAT, false, 4 * 4, 0);
gl.vertexAttribPointer(pr.locations['a_bottomright'], 2, gl.FLOAT, false, 4 * 4, 2 * 4);
gl.vertexAttribDivisor(pr.locations['a_topleft'], 1);
gl.vertexAttribDivisor(pr.locations['a_bottomright'], 1);
// Static draw (everything already bound)
gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, quad_count);
gl.vertexAttribDivisor(pr.locations['a_topleft'], 0);
gl.vertexAttribDivisor(pr.locations['a_bottomright'], 0);
} }
document.getElementById('debug-stats').innerHTML = ` document.getElementById('debug-stats').innerHTML = `

1
client/webgl_geometry.js

@ -229,6 +229,7 @@ function add_image(context, image_id, bitmap, p, width, height) {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.generateMipmap(gl.TEXTURE_2D);
} }
} }

4
client/webgl_listeners.js

@ -43,6 +43,7 @@ function debug_panel_init(state, context) {
document.getElementById('draw-bvh').addEventListener('change', (e) => { document.getElementById('draw-bvh').addEventListener('change', (e) => {
config.draw_bvh = e.target.checked; config.draw_bvh = e.target.checked;
schedule_draw(state, context);
}); });
document.getElementById('debug-begin-benchmark').addEventListener('click', (e) => { document.getElementById('debug-begin-benchmark').addEventListener('click', (e) => {
@ -51,7 +52,8 @@ function debug_panel_init(state, context) {
state.canvas.offset.y = config.benchmark.offset.y; state.canvas.offset.y = config.benchmark.offset.y;
const dz = (state.canvas.zoom_level > 0 ? config.zoom_delta : -config.zoom_delta); const dz = (state.canvas.zoom_level > 0 ? config.zoom_delta : -config.zoom_delta);
state.canvas.zoom = Math.pow(1.0 + dz, Math.abs(state.canvas.zoom_level)) state.canvas.target_zoom = Math.pow(1.0 + dz, Math.abs(state.canvas.zoom_level))
state.canvas.zoom = state.canvas.target_zoom;
state.debug.benchmark_mode = true; state.debug.benchmark_mode = true;

62
client/webgl_shaders.js

@ -270,6 +270,63 @@ const dots_fs_src = `#version 300 es
} }
`; `;
//
const iquad_vs_src = `#version 300 es
in vec2 a_topleft; // per-instance
in vec2 a_bottomright; // per-instance
uniform vec2 u_scale;
uniform vec2 u_res;
uniform vec2 u_translation;
out vec3 v_color;
void main() {
vec2 pos;
int vertex_index = gl_VertexID % 6;
if (vertex_index == 0) {
// top left
pos = a_topleft;
} else if (vertex_index == 1 || vertex_index == 5) {
// top right
pos = vec2(a_bottomright.x, a_topleft.y);
} else if (vertex_index == 2 || vertex_index == 4) {
// bottom left
pos = vec2(a_topleft.x, a_bottomright.y);
} else {
// bottom right
pos = a_bottomright;
}
v_color = vec3(
float(int(a_topleft.x) * 908125 % 255) / 255.0,
float(int(a_topleft.y) * 257722 % 255) / 255.0,
float(int(a_bottomright.y) * 826586 % 255) / 255.0
);
vec2 screen01 = (pos * u_scale + u_translation) / u_res;
vec2 screen02 = screen01 * 2.0;
screen02.y = 2.0 - screen02.y;
vec2 screen11 = screen02 - 1.0;
gl_Position = vec4(screen11, 0.0, 1.0);
}
`;
const iquad_fs_src = `#version 300 es
precision highp float;
layout(location = 0) out vec4 FragColor;
in vec3 v_color;
void main() {
FragColor = vec4(v_color, 0.5);
}
`;
function init_webgl(state, context) { function init_webgl(state, context) {
context.canvas = document.querySelector('#c'); context.canvas = document.querySelector('#c');
context.gl = context.canvas.getContext('webgl2', { context.gl = context.canvas.getContext('webgl2', {
@ -303,11 +360,15 @@ function init_webgl(state, context) {
const grid_vs = create_shader(gl, gl.VERTEX_SHADER, grid_vs_src); const grid_vs = create_shader(gl, gl.VERTEX_SHADER, grid_vs_src);
const iquad_vs = create_shader(gl, gl.VERTEX_SHADER, iquad_vs_src);
const iquad_fs = create_shader(gl, gl.FRAGMENT_SHADER, iquad_fs_src);
context.programs = { context.programs = {
'image': create_program(gl, quad_vs, quad_fs), 'image': create_program(gl, quad_vs, quad_fs),
'main': create_program(gl, sdf_vs, sdf_fs), 'main': create_program(gl, sdf_vs, sdf_fs),
'dots': create_program(gl, dots_vs, dots_fs), 'dots': create_program(gl, dots_vs, dots_fs),
'grid': create_program(gl, grid_vs, dots_fs), 'grid': create_program(gl, grid_vs, dots_fs),
'iquad': create_program(gl, iquad_vs, iquad_fs),
}; };
context.buffers = { context.buffers = {
@ -318,6 +379,7 @@ function init_webgl(state, context) {
'b_instance_grid': gl.createBuffer(), 'b_instance_grid': gl.createBuffer(),
'b_dot': gl.createBuffer(), 'b_dot': gl.createBuffer(),
'b_hud': gl.createBuffer(), 'b_hud': gl.createBuffer(),
'b_iquads': gl.createBuffer(),
}; };
context.textures = { context.textures = {

Loading…
Cancel
Save