diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index 30169e1..b5e4ade 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -14,8 +14,6 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC) { auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - drawP.compCache.disableRefresh = true; - std::unordered_set selectedComponents; std::function&)> fullyCollidedFunc = [&](const std::shared_ptr& bvhNode) { @@ -93,13 +91,61 @@ void DrawingProgramSelection::update() { selectionRectMin = selectionTransformCoords.from_space_world(initialSelectionAABB.min); selectionRectMax = selectionTransformCoords.from_space_world(initialSelectionAABB.max); + scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(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; + + switch(transformOpHappening) { + case TransformOperation::NONE: + if(drawP.controls.leftClick) { + 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; + transformOpHappening = TransformOperation::SCALE; + } + else if(mouse_collided_with_selection_aabb()) + transformOpHappening = TransformOperation::TRANSLATE; + else + deselect_all(); + } + break; + case TransformOperation::TRANSLATE: + if(drawP.controls.leftClickHeld) + selectionTransformCoords.translate(drawP.world.drawData.cam.c.dir_from_space(drawP.world.main.input.mouse.move)); + else + transformOpHappening = TransformOperation::NONE; + break; + case TransformOperation::SCALE: + if(drawP.controls.leftClickHeld) { + WorldVec centerToScaleStart = scaleData.startPos - scaleData.centerPos; + Vector2f centerToScaleStartInCamSpace = drawP.world.drawData.cam.c.normalized_dir_to_space(centerToScaleStart.normalized()); + Vector2f scaleCenterPointInCamSpace = drawP.world.drawData.cam.c.to_space(scaleData.centerPos); + scaleData.currentPos = drawP.world.drawData.cam.c.from_space(project_point_on_line(drawP.world.main.input.mouse.pos, scaleCenterPointInCamSpace, (scaleCenterPointInCamSpace + centerToScaleStartInCamSpace).eval())); + + WorldVec centerToScaleCurrent = scaleData.currentPos - scaleData.centerPos; + + WorldScalar centerToScaleStartNorm = centerToScaleStart.norm(); + WorldScalar centerToScaleCurrentNorm = centerToScaleCurrent.norm(); + bool isAnyNumberZero = centerToScaleCurrentNorm == WorldScalar(0) || centerToScaleStartNorm == WorldScalar(0); + if(!isAnyNumberZero) { + bool flipScale = centerToScaleStartNorm < centerToScaleCurrentNorm; + WorldScalar scaleAmount; + if(flipScale) + scaleAmount = centerToScaleCurrentNorm / centerToScaleStartNorm; + else + scaleAmount = centerToScaleStartNorm / centerToScaleCurrentNorm; + + selectionTransformCoords = scaleData.startingSelectionTransformCoords; + selectionTransformCoords.scale_about(scaleData.centerPos, scaleAmount, flipScale); + } + } + else + transformOpHappening = TransformOperation::NONE; + break; + case TransformOperation::ROTATE: + break; + } } } @@ -113,10 +159,18 @@ void DrawingProgramSelection::rebuild_cam_space() { camSpaceSelection = drawP.world.drawData.cam.c.world_collider_to_coords>(collideRectWorld); } +bool DrawingProgramSelection::mouse_collided_with_selection() { + return mouse_collided_with_selection_aabb() || mouse_collided_with_scale_point(); +} + bool DrawingProgramSelection::mouse_collided_with_selection_aabb() { return SCollision::collide(camSpaceSelection, drawP.world.main.input.mouse.pos); } +bool DrawingProgramSelection::mouse_collided_with_scale_point() { + return SCollision::collide(SCollision::Circle(scaleData.handlePoint, DRAG_POINT_RADIUS), drawP.world.main.input.mouse.pos); +} + void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& drawData) { if(is_something_selected()) { DrawData selectionDrawData = drawData; @@ -131,7 +185,6 @@ void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawData) { if(is_something_selected() && !camSpaceSelection.triangle.empty()) { - canvas->save(); SkPath selectionRectPath; selectionRectPath.moveTo(convert_vec2(camSpaceSelection.triangle[0].p[0])); selectionRectPath.lineTo(convert_vec2(camSpaceSelection.triangle[0].p[1])); @@ -140,6 +193,7 @@ void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawDat selectionRectPath.close(); SkPaint p{SkColor4f{0.3f, 0.6f, 0.9f, 0.4f}}; canvas->drawPath(selectionRectPath, p); - canvas->restore(); + + 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 2cca747..e0a5203 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -12,8 +12,11 @@ class DrawingProgramSelection { 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(); + bool mouse_collided_with_selection(); private: + bool mouse_collided_with_selection_aabb(); + bool mouse_collided_with_scale_point(); + void calculate_aabb(); void rebuild_cam_space(); @@ -28,7 +31,18 @@ class DrawingProgramSelection { DrawingProgramCache cache; DrawingProgram& drawP; - struct TranslationData { - bool happening = false; - } translation; + enum class TransformOperation { + NONE = 0, + TRANSLATE, + SCALE, + ROTATE + } transformOpHappening; + + struct ScaleData { + CoordSpaceHelper startingSelectionTransformCoords; + WorldVec startPos; + WorldVec centerPos; + WorldVec currentPos; + Vector2f handlePoint; + } scaleData; }; diff --git a/src/DrawingProgram/RectSelectTool.cpp b/src/DrawingProgram/RectSelectTool.cpp index 391ab2c..6304e70 100644 --- a/src/DrawingProgram/RectSelectTool.cpp +++ b/src/DrawingProgram/RectSelectTool.cpp @@ -44,7 +44,7 @@ void RectSelectTool::tool_update() { drawP.compCache.disableRefresh = false; if(drawP.controls.leftClick) { if(drawP.selection.is_something_selected()) { - if(!drawP.selection.mouse_collided_with_selection_aabb()) + if(!drawP.selection.mouse_collided_with_selection()) reset_tool(); } else { @@ -70,7 +70,6 @@ void RectSelectTool::tool_update() { drawP.selection.add_from_cam_coord_collider_to_selection(cC); controls.selectionMode = 0; - drawP.compCache.disableRefresh = true; } break; }