From 759f551cd36e0827b0c3ef062ae0786b96e51ff3 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Thu, 24 Jul 2025 19:35:51 +0300 Subject: [PATCH] Translation works on selection --- include/Helpers/Parallel.hpp | 14 ++++ src/CoordSpaceHelper.cpp | 17 +++++ src/CoordSpaceHelper.hpp | 6 ++ src/DrawComponents/DrawComponent.hpp | 2 - src/DrawingProgram/DrawingProgram.cpp | 23 +----- src/DrawingProgram/DrawingProgram.hpp | 2 +- .../DrawingProgramSelection.cpp | 76 +++++++++++++------ .../DrawingProgramSelection.hpp | 17 ++++- src/DrawingProgram/RectSelectTool.cpp | 17 ++++- 9 files changed, 119 insertions(+), 55 deletions(-) create mode 100644 include/Helpers/Parallel.hpp diff --git a/include/Helpers/Parallel.hpp b/include/Helpers/Parallel.hpp new file mode 100644 index 0000000..ee78dfd --- /dev/null +++ b/include/Helpers/Parallel.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#ifdef __APPLE__ + #define POOLSTL_STD_SUPPLEMENT + #include +#endif + +template void parallel_loop_container(ContainerType& c, std::function func) { +#ifdef __EMSCRIPTEN__ + std::for_each(c.begin(), c.end(), func); +#else + std::for_each(std::execution::par_unseq, c.begin(), c.end(), func); +#endif +} diff --git a/src/CoordSpaceHelper.cpp b/src/CoordSpaceHelper.cpp index 2d0edb1..487b99c 100644 --- a/src/CoordSpaceHelper.cpp +++ b/src/CoordSpaceHelper.cpp @@ -12,6 +12,15 @@ CoordSpaceHelper::CoordSpaceHelper(const WorldVec& initPos, const WorldScalar& i rotation(initRotation) {} +WorldVec rotate_world_coord(const WorldVec& a, double rotationAngle) { + FixedPoint::Number s = FixedPoint::Number(std::sin(rotationAngle)); + FixedPoint::Number c = FixedPoint::Number(std::cos(rotationAngle)); + return { + a.x().multiply_different_precision(c) - a.y().multiply_different_precision(s), + a.x().multiply_different_precision(s) + a.y().multiply_different_precision(c) + }; +} + Vector2f CoordSpaceHelper::to_space(const WorldVec& coord) const { return (Rotation2D(-rotation) * ((coord - pos) / inverseScale).cast()).cast(); } @@ -20,6 +29,14 @@ WorldVec CoordSpaceHelper::from_space(Vector2f coord) const { return ((Rotation2D(rotation) * coord.cast()).cast() * inverseScale + pos); } +WorldVec CoordSpaceHelper::to_space_world(const WorldVec& coord) const { + return rotate_world_coord(((coord - pos) / inverseScale), -rotation); +} + +WorldVec CoordSpaceHelper::from_space_world(const WorldVec& coord) const { + return rotate_world_coord(coord, rotation) * inverseScale + pos; +} + WorldScalar CoordSpaceHelper::scalar_from_space(float coord) const { return WorldScalar(coord) * inverseScale; } diff --git a/src/CoordSpaceHelper.hpp b/src/CoordSpaceHelper.hpp index c9934ab..3d9ec89 100644 --- a/src/CoordSpaceHelper.hpp +++ b/src/CoordSpaceHelper.hpp @@ -25,7 +25,13 @@ class CoordSpaceHelper { CoordSpaceHelper(const WorldVec& initPos, const WorldScalar& initInverseScale, double initRotation); Vector2f to_space(const WorldVec& coord) const; + + WorldVec from_space(Vector2f coord) const; + + WorldVec from_space_world(const WorldVec& coord) const; + WorldVec to_space_world(const WorldVec& coord) const; + WorldScalar scalar_from_space(float coord) const; float scalar_to_space(const WorldScalar& coord) const; WorldVec dir_from_space(Vector2f coord) const; diff --git a/src/DrawComponents/DrawComponent.hpp b/src/DrawComponents/DrawComponent.hpp index 86d70a4..78baab8 100644 --- a/src/DrawComponents/DrawComponent.hpp +++ b/src/DrawComponents/DrawComponent.hpp @@ -73,8 +73,6 @@ class DrawComponent { void server_update(MainServer& server, ServerClientID id); #ifndef IS_SERVER - bool selected = false; - std::chrono::time_point lastTransformTime; std::chrono::time_point lastUpdateTime; diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index be8987a..aaa0730 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -22,19 +22,7 @@ #include "../World.hpp" #include "../MainProgram.hpp" #include -#include -#ifdef __APPLE__ - #define POOLSTL_STD_SUPPLEMENT - #include -#endif - -template void parallel_loop_container(ContainerType& c, std::function func) { -#ifdef __EMSCRIPTEN__ - std::for_each(c.begin(), c.end(), func); -#else - std::for_each(std::execution::par_unseq, c.begin(), c.end(), func); -#endif -} +#include DrawingProgram::DrawingProgram(World& initWorld): world(initWorld), @@ -444,7 +432,6 @@ void DrawingProgram::reset_tools() { ellipseDrawTool.reset_tool(); editTool.reset_tool(); eraserTool.reset_tool(); - reset_selection(); } void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a) { @@ -464,11 +451,6 @@ void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a) compCache.force_rebuild(components.client_list()); } -void DrawingProgram::reset_selection() { - for(auto& c : components.client_list()) - c->obj->selected = false; -} - void DrawingProgram::add_undo_place_component(uint64_t placement, const std::shared_ptr& comp) { world.undo.push(UndoManager::UndoRedoPair{ [&, comp]() { @@ -573,8 +555,9 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) { drawProgCacheCanvas->clear(SkColor4f{0.0f, 0.0f, 0.0f, 0.0f}); compCache.refresh_all_draw_cache(drawData); compCache.draw_components_to_canvas(drawProgCacheCanvas, drawData); + selection.draw_components(drawProgCacheCanvas, drawData); canvas->drawImage(world.main.drawProgCache.surface->makeTemporaryImage(), 0, 0); - selection.draw(canvas, drawData); + selection.draw_gui(canvas, drawData); } } diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index ad5f1f8..3b8df69 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -68,7 +68,6 @@ class DrawingProgram { void add_file_to_canvas_by_path_execute(const std::string& filePath, Vector2f dropPos); - void reset_selection(); void reset_tools(); void drag_drop_update(); @@ -135,4 +134,5 @@ class DrawingProgram { friend class EditTool; friend class ImageTool; friend class DrawingProgramCache; + friend class DrawingProgramSelection; }; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index 6be71d3..30169e1 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -2,6 +2,9 @@ #include "DrawingProgram.hpp" #include "../World.hpp" #include "../MainProgram.hpp" +#include +#include +#include DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): cache(initDrawP), @@ -56,21 +59,24 @@ bool DrawingProgramSelection::is_something_selected() { void DrawingProgramSelection::calculate_aabb() { if(is_something_selected()) { - selectionAABB = (*selectedSet.begin())->obj->worldAABB.value(); + initialSelectionAABB = (*selectedSet.begin())->obj->worldAABB.value(); for(auto& c : selectedSet) - selectionAABB.include_aabb_in_bounds(c->obj->worldAABB.value()); + initialSelectionAABB.include_aabb_in_bounds(c->obj->worldAABB.value()); } } void DrawingProgramSelection::deselect_all() { - for(auto& obj : selectedSet) { - obj->obj->coords = selectionTransformCoords.other_coord_space_from_this_space(obj->obj->coords); - obj->obj->final_update(drawP); + if(is_something_selected()) { + std::vector a(selectedSet.begin(), selectedSet.end()); + parallel_loop_container(a, [&](auto& obj) { + obj->obj->coords = selectionTransformCoords.other_coord_space_from_this_space(obj->obj->coords); + obj->obj->final_update(drawP, false); + }); + selectedSet.clear(); + cache.clear(); + selectionTransformCoords = CoordSpaceHelper(); + drawP.compCache.force_rebuild(drawP.components.client_list()); } - selectedSet.clear(); - cache.clear(); - selectionTransformCoords = CoordSpaceHelper(); - drawP.compCache.force_rebuild(drawP.components.client_list()); } void DrawingProgramSelection::update() { @@ -79,26 +85,39 @@ void DrawingProgramSelection::update() { cache.force_rebuild(std::vector(selectedSet.begin(), selectedSet.end())); if(drawP.world.main.input.key(InputManager::KEY_DRAW_UNSELECT).pressed) deselect_all(); - if(drawP.world.main.input.key(InputManager::KEY_TEXT_UP).held) - selectionTransformCoords.translate(WorldVec{0, -drawP.world.drawData.cam.c.inverseScale}); - if(drawP.world.main.input.key(InputManager::KEY_TEXT_DOWN).held) - selectionTransformCoords.translate(WorldVec{0, drawP.world.drawData.cam.c.inverseScale}); - if(drawP.world.main.input.key(InputManager::KEY_TEXT_LEFT).held) - selectionTransformCoords.translate(WorldVec{-drawP.world.drawData.cam.c.inverseScale, 0}); - if(drawP.world.main.input.key(InputManager::KEY_TEXT_RIGHT).held) - selectionTransformCoords.translate(WorldVec{drawP.world.drawData.cam.c.inverseScale, 0}); if(drawP.world.main.input.key(InputManager::KEY_TEXT_CTRL).held) selectionTransformCoords.scale_about_double(selectionTransformCoords.pos, 1.01); if(drawP.world.main.input.key(InputManager::KEY_TEXT_SHIFT).held) selectionTransformCoords.scale_about_double(selectionTransformCoords.pos, 0.99); + + selectionRectMin = selectionTransformCoords.from_space_world(initialSelectionAABB.min); + selectionRectMax = selectionTransformCoords.from_space_world(initialSelectionAABB.max); + + rebuild_cam_space(); + if(drawP.controls.leftClick && mouse_collided_with_selection_aabb()) + translation.happening = true; + else if(drawP.controls.leftClickHeld && translation.happening) + selectionTransformCoords.translate(drawP.world.drawData.cam.c.dir_from_space(drawP.world.main.input.mouse.move)); + else + translation.happening = false; } } -bool DrawingProgramSelection::mouse_collided_with_selection_aabb() { - return false; +void DrawingProgramSelection::rebuild_cam_space() { + std::array collideRectTriangleVerticesWorld = triangle_from_rect_points(selectionRectMin, selectionRectMax); + SCollision::ColliderCollection collideRectWorld; + collideRectWorld.triangle.emplace_back(collideRectTriangleVerticesWorld[0], collideRectTriangleVerticesWorld[1], collideRectTriangleVerticesWorld[2]); + collideRectWorld.triangle.emplace_back(collideRectTriangleVerticesWorld[0], collideRectTriangleVerticesWorld[2], collideRectTriangleVerticesWorld[3]); + collideRectWorld.recalculate_bounds(); + + camSpaceSelection = drawP.world.drawData.cam.c.world_collider_to_coords>(collideRectWorld); } -void DrawingProgramSelection::draw(SkCanvas* canvas, const DrawData& drawData) { +bool DrawingProgramSelection::mouse_collided_with_selection_aabb() { + return SCollision::collide(camSpaceSelection, drawP.world.main.input.mouse.pos); +} + +void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& drawData) { if(is_something_selected()) { DrawData selectionDrawData = drawData; selectionDrawData.cam.c = selectionTransformCoords.other_coord_space_to_this_space(selectionDrawData.cam.c); @@ -107,13 +126,20 @@ void DrawingProgramSelection::draw(SkCanvas* canvas, const DrawData& drawData) { cache.refresh_all_draw_cache(selectionDrawData); cache.draw_components_to_canvas(canvas, selectionDrawData); + } +} +void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawData) { + if(is_something_selected() && !camSpaceSelection.triangle.empty()) { canvas->save(); - selectionTransformCoords.transform_sk_canvas(canvas, selectionDrawData); - Vector2f minRectPos = selectionTransformCoords.to_space(selectionAABB.min); - Vector2f maxRectPos = selectionTransformCoords.to_space(selectionAABB.max); - SkPaint p{SkColor4f{0.0f, 0.0f, 1.0f, 0.3f}}; - canvas->drawRect(SkRect::MakeLTRB(minRectPos.x(), minRectPos.y(), maxRectPos.x(), maxRectPos.y()), p); + SkPath selectionRectPath; + selectionRectPath.moveTo(convert_vec2(camSpaceSelection.triangle[0].p[0])); + selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[0].p[1])); + selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[0].p[2])); + selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[1].p[2])); + selectionRectPath.close(); + SkPaint p{SkColor4f{0.3f, 0.6f, 0.9f, 0.4f}}; + canvas->drawPath(selectionRectPath, p); canvas->restore(); } } diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index 9d3b8d9..2cca747 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -9,15 +9,26 @@ class DrawingProgramSelection { void add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC); void deselect_all(); void update(); - void draw(SkCanvas* canvas, const DrawData& drawData); + void draw_components(SkCanvas* canvas, const DrawData& drawData); + void draw_gui(SkCanvas* canvas, const DrawData& drawData); bool is_something_selected(); + bool mouse_collided_with_selection_aabb(); private: void calculate_aabb(); - bool mouse_collided_with_selection_aabb(); + void rebuild_cam_space(); + + SCollision::AABB initialSelectionAABB; + SCollision::ColliderCollection camSpaceSelection; + + WorldVec selectionRectMin; + WorldVec selectionRectMax; - SCollision::AABB selectionAABB; CoordSpaceHelper selectionTransformCoords; std::unordered_set selectedSet; DrawingProgramCache cache; DrawingProgram& drawP; + + struct TranslationData { + bool happening = false; + } translation; }; diff --git a/src/DrawingProgram/RectSelectTool.cpp b/src/DrawingProgram/RectSelectTool.cpp index e016cc0..391ab2c 100644 --- a/src/DrawingProgram/RectSelectTool.cpp +++ b/src/DrawingProgram/RectSelectTool.cpp @@ -33,7 +33,9 @@ void RectSelectTool::gui_toolbox() { } void RectSelectTool::reset_tool() { + drawP.selection.deselect_all(); controls = RectSelectControls(); + drawP.compCache.disableRefresh = false; } void RectSelectTool::tool_update() { @@ -41,10 +43,16 @@ void RectSelectTool::tool_update() { case 0: { drawP.compCache.disableRefresh = false; if(drawP.controls.leftClick) { - reset_tool(); - controls.coords = drawP.world.drawData.cam.c; - controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world); - controls.selectionMode = 1; + if(drawP.selection.is_something_selected()) { + if(!drawP.selection.mouse_collided_with_selection_aabb()) + reset_tool(); + } + else { + reset_tool(); + controls.coords = drawP.world.drawData.cam.c; + controls.selectStartAt = controls.coords.get_mouse_pos(drawP.world); + controls.selectionMode = 1; + } } break; } @@ -62,6 +70,7 @@ void RectSelectTool::tool_update() { drawP.selection.add_from_cam_coord_collider_to_selection(cC); controls.selectionMode = 0; + drawP.compCache.disableRefresh = true; } break; }