From fea287400434de7f01f7250e50bf614b0325277d Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Tue, 17 Sep 2024 21:47:38 +0300 Subject: [PATCH] Merge scale and move local history, fixing undo for image move/scale --- README.txt | 14 ++++++++++- client/client_recv.js | 24 ++---------------- client/undo.js | 53 ++++++++++++++++++++++++++++++--------- client/webgl_geometry.js | 8 +++--- client/webgl_listeners.js | 2 +- 5 files changed, 60 insertions(+), 41 deletions(-) diff --git a/README.txt b/README.txt index 762eb38..333fa36 100644 --- a/README.txt +++ b/README.txt @@ -16,8 +16,9 @@ Release: + Stroke previews get connected when drawn without panning on touch devices + Redraw HTML (cursors) on local canvas moves + New strokes dissapear on the HMH desk + + 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 - - Undo history of moving and scaling images seems messed up + - Weird clipping on HMH desk full zoomout after running "benchmark" - Debug - Restore ability to limit event range * Listeners/events/multiplayer @@ -30,6 +31,7 @@ Release: + Be able to have multiple "current" strokes per player. In case of bad internet this can happen! - Do NOT use session id as player id LUL - Save events to indexeddb (as some kind of a blob), restore on reconnect and page reload + - Handle out of space - Local prediction for tools! - Immediately commit a stroke to the canvas, change order if earlier strokes arrive - Show my own image immediately, show placeholders while images are loading (add bitmap size to event) @@ -52,12 +54,17 @@ Release: - Redo + Snapping to grid - Snapping to other points? + - Color picker should work for ruler + - Show previous color in color picker preview + - Stick picker preview to cursor * Polish + Use typedvector where appropriate - Show what's happening while the desk is loading (downloading, processing, uploading to gpu) - Settings panel for config values (including the setting for "offline mode") - Set up VAOs - We are calling "geometry_prepare_stroke" twice for some reason + - Replace "geometry_add_dummy_stroke" with something not [so] cursed + - Automatically extract locations from shaders (see nitka project for code examples) - Presentation / "marketing" - Title (InfiNotes? MegaDesk?) - Icon @@ -80,6 +87,11 @@ Bonus: + Dots pattern + Grid pattern - Menu option + - Offline mode + - Only one user + - No server, everything applied immediately + - Allow export to file + - Save to browser storage (probaby indexed db + recent events in localstorage) Bonus-bonus: - Actually infinite canvas (replace floats with something, some kind of fixed point scheme? chunks? multilevel scheme?) diff --git a/client/client_recv.js b/client/client_recv.js index 3f39dd7..154125d 100644 --- a/client/client_recv.js +++ b/client/client_recv.js @@ -407,16 +407,7 @@ function handle_event(state, context, event, options = {}) { if (image) { // if (config.debug_print) console.debug('move image', image_id, 'to', image_event.x, image_event.y); - if (image.move_head < image.move_history.length) { - image.move_history[image.move_head] = event.x; - image.move_history[image.move_head + 1] = event.y; - } else { - image.move_history.push(event.x, event.y); - } - - image.move_head += 2; - image.at.x = event.x; - image.at.y = event.y; + push_image_move(image, event.x, event.y); need_draw = true; } @@ -429,18 +420,7 @@ function handle_event(state, context, event, options = {}) { const image = get_image(context, image_id); if (image !== null) { - if (image.scale_head < image.scale_history.length) { - image.scale_history[image.scale_head] = image.at.x; - image.scale_history[image.scale_head + 1] = image.at.y; - image.scale_history[image.scale_head + 2] = image.width; - image.scale_history[image.scale_head + 3] = image.height; - } else { - image.scale_history.push(image.at.x, image.at.y, image.width, image.height); - } - - image.scale_head += 4; - - scale_image(context, image, event.corner, {'x': event.x, 'y': event.y}); + push_image_scale(image, event.corner, event.x, event.y); need_draw = true; } diff --git a/client/undo.js b/client/undo.js index 869213d..862299c 100644 --- a/client/undo.js +++ b/client/undo.js @@ -42,9 +42,7 @@ function undo(state, context, event, options) { other_event.deleted = true; const image = get_image(context, other_event.image_id); if (image !== null) { - image.move_head -= 2; - image.at.x = image.move_history[image.move_head - 2]; - image.at.y = image.move_history[image.move_head - 1]; + pop_image_transform(image); need_draw = true; } else { console.warning('Undo image move for a non-existent image'); @@ -56,15 +54,7 @@ function undo(state, context, event, options) { other_event.deleted = true; const image = get_image(context, other_event.image_id); if (image !== null) { - image.scale_head -= 4; - - // NEXT: merge move and scale. Otherwise we can't know - // that there have been move events inbetween scale - - image.at.x = image.scale_history[image.scale_head - 4]; - image.at.y = image.scale_history[image.scale_head - 3]; - image.width = image.scale_history[image.scale_head - 2]; - image.height = image.scale_history[image.scale_head - 1]; + pop_image_transform(image); need_draw = true; } else { console.warning('Undo image scale for a non-existent image'); @@ -101,3 +91,42 @@ function undo(state, context, event, options) { function redo() { console.log('TODO'); } + +function push_image_move(image, x, y) { + if (image.transform_head < image.transform_history.length) { + image.transform_history[image.transform_head] = image.at.x; + image.transform_history[image.transform_head + 1] = image.at.y; + image.transform_history[image.transform_head + 2] = image.width; + image.transform_history[image.transform_head + 3] = image.height; + } else { + image.transform_history.push(image.at.x, image.at.y, image.width, image.height); + } + + image.at.x = x; + image.at.y = y; + + image.transform_head += 4; +} + +function push_image_scale(image, corner, x, y) { + if (image.transform_head < image.transform_history.length) { + image.transform_history[image.transform_head] = image.at.x; + image.transform_history[image.transform_head + 1] = image.at.y; + image.transform_history[image.transform_head + 2] = image.width; + image.transform_history[image.transform_head + 3] = image.height; + } else { + image.transform_history.push(image.at.x, image.at.y, image.width, image.height); + } + + scale_image(image, corner, {'x': x, 'y': y}); + + image.transform_head += 4; +} + +function pop_image_transform(image, corner, x, y) { + image.transform_head -= 4; + image.at.x = image.transform_history[image.transform_head - 4]; + image.at.y = image.transform_history[image.transform_head - 3]; + image.width = image.transform_history[image.transform_head - 2]; + image.height = image.transform_history[image.transform_head - 1]; +} diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index 0344f34..0235652 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -209,10 +209,8 @@ function add_image(context, image_id, bitmap, p, width, height) { 'raw_at': {...p}, 'width': width, 'height': height, - 'move_history': [ p.x, p.y ], - 'scale_history': [ p.x, p.y, width, height ], - 'move_head': 2, - 'scale_head': 4, + 'transform_history': [ p.x, p.y, width, height ], + 'transform_head': 4, }; context.images.push(entry); @@ -234,7 +232,7 @@ function add_image(context, image_id, bitmap, p, width, height) { } } -function scale_image(context, image, corner, canvasp) { +function scale_image(image, corner, canvasp) { let new_width, new_height; const old_x2 = image.at.x + image.width; diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js index 2f6d03f..2c75231 100644 --- a/client/webgl_listeners.js +++ b/client/webgl_listeners.js @@ -386,7 +386,7 @@ function mousemove(e, state, context) { if (state.imagescaling) { const image = get_image(context, state.active_image); - scale_image(context, image, state.scaling_corner, canvasp); + scale_image(image, state.scaling_corner, canvasp); do_draw = true; }