From 8a36bc4b6dc11e9f6d66fd598a16fbea0dfe8ebd Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Fri, 25 Jul 2025 10:00:39 +0300 Subject: [PATCH] Rotation works --- src/CoordSpaceHelper.cpp | 22 +++++- src/CoordSpaceHelper.hpp | 2 + src/DrawingProgram/DrawingProgram.cpp | 2 + .../DrawingProgramSelection.cpp | 78 +++++++++++++++---- .../DrawingProgramSelection.hpp | 21 ++++- 5 files changed, 103 insertions(+), 22 deletions(-) diff --git a/src/CoordSpaceHelper.cpp b/src/CoordSpaceHelper.cpp index 487b99c..00d9c64 100644 --- a/src/CoordSpaceHelper.cpp +++ b/src/CoordSpaceHelper.cpp @@ -127,22 +127,36 @@ std::vector CoordSpaceHelper::from_space(const std::vector& return toRet; } +std::vector CoordSpaceHelper::to_space_world(const std::vector& coord) const { + std::vector toRet(coord.size()); + for(size_t i = 0; i < coord.size(); i++) + toRet[i] = to_space_world(coord[i]); + return toRet; +} + +std::vector CoordSpaceHelper::from_space_world(const std::vector& coord) const { + std::vector toRet(coord.size()); + for(size_t i = 0; i < coord.size(); i++) + toRet[i] = from_space_world(coord[i]); + return toRet; +} + Vector2f CoordSpaceHelper::get_mouse_pos(const World& w) const { return to_space(w.drawData.cam.c.from_space(w.main.input.mouse.pos)); } CoordSpaceHelper CoordSpaceHelper::other_coord_space_to_this_space(const CoordSpaceHelper& other) const { CoordSpaceHelper toRet; - toRet.pos = (other.pos - pos) / inverseScale; - toRet.rotation = other.rotation; + toRet.pos = to_space_world(other.pos); + toRet.rotation = other.rotation - rotation; toRet.inverseScale = other.inverseScale / inverseScale; return toRet; } CoordSpaceHelper CoordSpaceHelper::other_coord_space_from_this_space(const CoordSpaceHelper& other) const { CoordSpaceHelper toRet; - toRet.pos = (other.pos * inverseScale) + pos; - toRet.rotation = other.rotation; + toRet.pos = from_space_world(other.pos); + toRet.rotation = other.rotation + rotation; toRet.inverseScale = other.inverseScale * inverseScale; return toRet; } diff --git a/src/CoordSpaceHelper.hpp b/src/CoordSpaceHelper.hpp index 3d9ec89..24b4cd6 100644 --- a/src/CoordSpaceHelper.hpp +++ b/src/CoordSpaceHelper.hpp @@ -74,6 +74,8 @@ class CoordSpaceHelper { //float scalar_to_space(WorldScalar coord) const; std::vector to_space(const std::vector& coord) const; std::vector from_space(const std::vector& coord) const; + std::vector to_space_world(const std::vector& coord) const; + std::vector from_space_world(const std::vector& coord) const; void translate(const WorldVec& translation); void scale(const WorldScalar& scaleAmount); diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index aaa0730..26b9837 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -555,7 +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); + drawProgCacheCanvas->saveLayerAlphaf(nullptr, 1.0f); selection.draw_components(drawProgCacheCanvas, drawData); + drawProgCacheCanvas->restore(); canvas->drawImage(world.main.drawProgCache.surface->makeTemporaryImage(), 0, 0); selection.draw_gui(canvas, drawData); } diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index b5e4ade..5563cd2 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -6,6 +6,9 @@ #include #include +#define ROTATION_POINT_RADIUS_MULTIPLIER 0.7f +#define ROTATION_POINTS_DISTANCE 20.0f + DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): cache(initDrawP), drawP(initDrawP) @@ -49,6 +52,7 @@ void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCo for(auto& obj : selectedSet) cache.add_component(obj); calculate_aabb(); + calculate_initial_rotate_center_location(); } bool DrawingProgramSelection::is_something_selected() { @@ -74,6 +78,7 @@ void DrawingProgramSelection::deselect_all() { cache.clear(); selectionTransformCoords = CoordSpaceHelper(); drawP.compCache.force_rebuild(drawP.components.client_list()); + transformOpHappening = TransformOperation::NONE; } } @@ -83,15 +88,15 @@ 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_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); + selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min); + selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left()); + selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max); + selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right()); scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(initialSelectionAABB.max)); + rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(rotateData.centerPos)); + rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle); rebuild_cam_space(); @@ -101,9 +106,16 @@ void DrawingProgramSelection::update() { if(mouse_collided_with_scale_point()) { scaleData.currentPos = scaleData.startPos = drawP.world.get_mouse_world_pos(); scaleData.centerPos = selectionTransformCoords.from_space_world(initialSelectionAABB.center()); - scaleData.startingSelectionTransformCoords = selectionTransformCoords; + startingSelectionTransformCoords = selectionTransformCoords; transformOpHappening = TransformOperation::SCALE; } + else if(mouse_collided_with_rotate_center_handle_point()) + transformOpHappening = TransformOperation::ROTATE_RELOCATE_CENTER; + else if(mouse_collided_with_rotate_handle_point()) { + rotateData.rotationAngle = 0.0; + startingSelectionTransformCoords = selectionTransformCoords; + transformOpHappening = TransformOperation::ROTATE; + } else if(mouse_collided_with_selection_aabb()) transformOpHappening = TransformOperation::TRANSLATE; else @@ -113,8 +125,10 @@ void DrawingProgramSelection::update() { case TransformOperation::TRANSLATE: if(drawP.controls.leftClickHeld) selectionTransformCoords.translate(drawP.world.drawData.cam.c.dir_from_space(drawP.world.main.input.mouse.move)); - else + else { transformOpHappening = TransformOperation::NONE; + calculate_initial_rotate_center_location(); + } break; case TransformOperation::SCALE: if(drawP.controls.leftClickHeld) { @@ -136,31 +150,50 @@ void DrawingProgramSelection::update() { else scaleAmount = centerToScaleStartNorm / centerToScaleCurrentNorm; - selectionTransformCoords = scaleData.startingSelectionTransformCoords; + selectionTransformCoords = startingSelectionTransformCoords; selectionTransformCoords.scale_about(scaleData.centerPos, scaleAmount, flipScale); } } + else { + transformOpHappening = TransformOperation::NONE; + calculate_initial_rotate_center_location(); + } + break; + case TransformOperation::ROTATE_RELOCATE_CENTER: + if(drawP.controls.leftClickHeld) + rotateData.centerPos = selectionTransformCoords.to_space_world(drawP.world.get_mouse_world_pos()); else transformOpHappening = TransformOperation::NONE; break; case TransformOperation::ROTATE: + if(drawP.controls.leftClickHeld) { + Vector2f rotationPointDiff = drawP.world.main.input.mouse.pos - rotateData.centerHandlePoint; + rotateData.rotationAngle = std::atan2(rotationPointDiff.y(), rotationPointDiff.x()); + selectionTransformCoords = startingSelectionTransformCoords; + selectionTransformCoords.rotate_about(selectionTransformCoords.from_space_world(rotateData.centerPos), rotateData.rotationAngle); + } + else + transformOpHappening = TransformOperation::NONE; break; } } } 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.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[1], selectionRectPoints[2]); + collideRectWorld.triangle.emplace_back(selectionRectPoints[0], selectionRectPoints[2], selectionRectPoints[3]); collideRectWorld.recalculate_bounds(); camSpaceSelection = drawP.world.drawData.cam.c.world_collider_to_coords>(collideRectWorld); } +void DrawingProgramSelection::calculate_initial_rotate_center_location() { + rotateData.centerPos = initialSelectionAABB.center(); +} + bool DrawingProgramSelection::mouse_collided_with_selection() { - return mouse_collided_with_selection_aabb() || mouse_collided_with_scale_point(); + return mouse_collided_with_selection_aabb() || mouse_collided_with_scale_point() || mouse_collided_with_rotate_center_handle_point() || mouse_collided_with_rotate_handle_point(); } bool DrawingProgramSelection::mouse_collided_with_selection_aabb() { @@ -171,6 +204,18 @@ bool DrawingProgramSelection::mouse_collided_with_scale_point() { return SCollision::collide(SCollision::Circle(scaleData.handlePoint, DRAG_POINT_RADIUS), drawP.world.main.input.mouse.pos); } +bool DrawingProgramSelection::mouse_collided_with_rotate_center_handle_point() { + return SCollision::collide(SCollision::Circle(rotateData.centerHandlePoint, DRAG_POINT_RADIUS), drawP.world.main.input.mouse.pos); +} + +bool DrawingProgramSelection::mouse_collided_with_rotate_handle_point() { + return SCollision::collide(SCollision::Circle(rotateData.handlePoint, DRAG_POINT_RADIUS * ROTATION_POINT_RADIUS_MULTIPLIER), drawP.world.main.input.mouse.pos); +} + +Vector2f DrawingProgramSelection::get_rotation_point_pos_from_angle(double angle) { + return Vector2f{rotateData.centerHandlePoint + ROTATION_POINTS_DISTANCE * Vector2f{std::cos(angle), std::sin(angle)}}; +} + void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& drawData) { if(is_something_selected()) { DrawData selectionDrawData = drawData; @@ -194,6 +239,11 @@ void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawDat SkPaint p{SkColor4f{0.3f, 0.6f, 0.9f, 0.4f}}; canvas->drawPath(selectionRectPath, p); - drawP.draw_drag_circle(canvas, scaleData.handlePoint, {0.1f, 0.9f, 0.9f, 1.0f}, drawData); + if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE || transformOpHappening == TransformOperation::ROTATE_RELOCATE_CENTER) + drawP.draw_drag_circle(canvas, rotateData.centerHandlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData); + if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::ROTATE) + drawP.draw_drag_circle(canvas, rotateData.handlePoint, {0.9f, 0.5f, 0.1f, 1.0f}, drawData, ROTATION_POINT_RADIUS_MULTIPLIER); + if(transformOpHappening == TransformOperation::NONE || transformOpHappening == TransformOperation::SCALE) + drawP.draw_drag_circle(canvas, scaleData.handlePoint, {0.1f, 0.9f, 0.9f, 1.0f}, drawData); } } diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index e0a5203..52ac1ec 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -16,15 +16,19 @@ class DrawingProgramSelection { private: bool mouse_collided_with_selection_aabb(); bool mouse_collided_with_scale_point(); + bool mouse_collided_with_rotate_center_handle_point(); + bool mouse_collided_with_rotate_handle_point(); void calculate_aabb(); + void calculate_initial_rotate_center_location(); void rebuild_cam_space(); + Vector2f get_rotation_point_pos_from_angle(double angle); + SCollision::AABB initialSelectionAABB; SCollision::ColliderCollection camSpaceSelection; - WorldVec selectionRectMin; - WorldVec selectionRectMax; + std::array selectionRectPoints; CoordSpaceHelper selectionTransformCoords; std::unordered_set selectedSet; @@ -35,14 +39,23 @@ class DrawingProgramSelection { NONE = 0, TRANSLATE, SCALE, + ROTATE_RELOCATE_CENTER, ROTATE - } transformOpHappening; + } transformOpHappening = TransformOperation::NONE; + + CoordSpaceHelper startingSelectionTransformCoords; struct ScaleData { - CoordSpaceHelper startingSelectionTransformCoords; WorldVec startPos; WorldVec centerPos; WorldVec currentPos; Vector2f handlePoint; } scaleData; + + struct RotationData { + WorldVec centerPos; + Vector2f centerHandlePoint; + Vector2f handlePoint; + double rotationAngle; + } rotateData; };