diff --git a/assets/icons/editor/snap05.png b/assets/icons/editor/snap05.png new file mode 100644 index 0000000..17e732b Binary files /dev/null and b/assets/icons/editor/snap05.png differ diff --git a/assets/icons/editor/snap1.png b/assets/icons/editor/snap1.png new file mode 100644 index 0000000..d96eba1 Binary files /dev/null and b/assets/icons/editor/snap1.png differ diff --git a/assets/icons/editor/snapoff.png b/assets/icons/editor/snapoff.png new file mode 100644 index 0000000..374ddfe Binary files /dev/null and b/assets/icons/editor/snapoff.png differ diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index 0168bd5..bbe2898 100644 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -2,10 +2,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -14,6 +16,7 @@ #include "datatypes/cframe.h" #include "editorcommon.h" +#include "mainwindow.h" #include "objects/handles.h" #include "physics/util.h" #include "qcursor.h" @@ -166,16 +169,28 @@ void MainGLWidget::handleHandleDrag(QMouseEvent* evt) { glm::vec3 handlePoint, rb; get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb); - if (selectedTool == SelectedTool::MOVE) - editorToolHandles->adornee->lock()->cframe = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint); - else if (selectedTool == SelectedTool::SCALE) { + if (selectedTool == SelectedTool::MOVE) { + glm::vec3 newPos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position(); + glm::vec3 oldPos = editorToolHandles->adornee->lock()->cframe.Position(); + glm::vec3 diff = newPos - oldPos; + + // Apply snapping + if (snappingFactor()) diff = glm::floor(diff / snappingFactor()) * snappingFactor(); + newPos = diff + oldPos; + + editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe.Rotation() + newPos; + } else if (selectedTool == SelectedTool::SCALE) { glm::vec3 handlePos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position(); // Find change in handles, and negate difference in sign between axes glm::vec3 diff = handlePos - glm::vec3(editorToolHandles->adornee->lock()->position()); + + // Apply snapping + if (snappingFactor()) diff = glm::floor(diff / snappingFactor()) * snappingFactor(); + editorToolHandles->adornee->lock()->size += diff * glm::sign(draggingHandle->normal); - // If alt is not pressed, also reposition the part such that only the dragged side gets lengthened + // If ctrl is not pressed, also reposition the part such that only the dragged side gets lengthened if (!(evt->modifiers() & Qt::ControlModifier)) editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe + (diff / 2.0f); } @@ -297,4 +312,17 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) { void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) { if (evt->key() == Qt::Key_W || evt->key() == Qt::Key_S) moveZ = 0; else if (evt->key() == Qt::Key_A || evt->key() == Qt::Key_D) moveX = 0; +} + +MainWindow* MainGLWidget::mainWindow() { + return dynamic_cast(window()); +} + +float MainGLWidget::snappingFactor() { + switch (mainWindow()->snappingMode) { + case GridSnappingMode::SNAP_1_STUD: return 1; + case GridSnappingMode::SNAP_05_STUDS: return 0.5; + case GridSnappingMode::SNAP_OFF: return 0; + } + return 0; } \ No newline at end of file diff --git a/editor/mainglwidget.h b/editor/mainglwidget.h index c596f65..8998f6e 100644 --- a/editor/mainglwidget.h +++ b/editor/mainglwidget.h @@ -1,6 +1,7 @@ #ifndef MAINGLWIDGET_H #define MAINGLWIDGET_H +#include "mainwindow.h" #include "objects/part.h" #include "qevent.h" #include @@ -31,6 +32,9 @@ protected: void mouseReleaseEvent(QMouseEvent* evt) override; void keyPressEvent(QKeyEvent* evt) override; void keyReleaseEvent(QKeyEvent* evt) override; + + MainWindow* mainWindow(); + float snappingFactor(); }; #endif // MAINGLWIDGET_H diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index a53befe..8a53f19 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -40,11 +40,18 @@ MainWindow::MainWindow(QWidget *parent) ConnectSelectionChangeHandler(); - connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = SelectedTool::SELECT; updateSelectedTool(); }); - connect(ui->actionToolMove, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::MOVE : SelectedTool::SELECT; updateSelectedTool(); }); - connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateSelectedTool(); }); - connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateSelectedTool(); }); + connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = SelectedTool::SELECT; updateToolbars(); }); + connect(ui->actionToolMove, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::MOVE : SelectedTool::SELECT; updateToolbars(); }); + connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateToolbars(); }); + connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateToolbars(); }); ui->actionToolSelect->setChecked(true); + selectedTool = SelectedTool::SELECT; + + connect(ui->actionGridSnap1, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_1_STUD; updateToolbars(); }); + connect(ui->actionGridSnap05, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_05_STUDS; updateToolbars(); }); + connect(ui->actionGridSnapOff, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_OFF; updateToolbars(); }); + ui->actionGridSnap1->setChecked(true); + snappingMode = GridSnappingMode::SNAP_1_STUD; connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() { simulationPlaying = !simulationPlaying; @@ -80,7 +87,7 @@ MainWindow::MainWindow(QWidget *parent) }); addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) { - updateSelectedTool(); + updateToolbars(); }); // ui->explorerView->Init(ui); @@ -134,12 +141,16 @@ void MainWindow::timerEvent(QTimerEvent* evt) { ui->mainWidget->updateCycle(); } -void MainWindow::updateSelectedTool() { +void MainWindow::updateToolbars() { ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT); ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE); ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE); ui->actionToolRotate->setChecked(selectedTool == SelectedTool::ROTATE); + ui->actionGridSnap1->setChecked(snappingMode == GridSnappingMode::SNAP_1_STUD); + ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS); + ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF); + if (selectedTool == SelectedTool::MOVE) editorToolHandles->worldMode = true; if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false; diff --git a/editor/mainwindow.h b/editor/mainwindow.h index 4879fe0..4dd279e 100644 --- a/editor/mainwindow.h +++ b/editor/mainwindow.h @@ -8,6 +8,12 @@ #include #include +enum GridSnappingMode { + SNAP_1_STUD, + SNAP_05_STUDS, + SNAP_OFF, +}; + QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; @@ -22,11 +28,13 @@ public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); + GridSnappingMode snappingMode; + Ui::MainWindow *ui; private: QBasicTimer timer; - void updateSelectedTool(); + void updateToolbars(); void timerEvent(QTimerEvent*) override; void ConnectSelectionChangeHandler(); }; diff --git a/editor/mainwindow.ui b/editor/mainwindow.ui index f4bf562..af91020 100644 --- a/editor/mainwindow.ui +++ b/editor/mainwindow.ui @@ -41,7 +41,7 @@ 0 0 1027 - 29 + 22 @@ -115,6 +115,10 @@ + + + + @@ -257,6 +261,60 @@ F5 + + + true + + + + assets/icons/editor/snap1.pngassets/icons/editor/snap1.png + + + 1-Stud Snapping + + + Set grid snapping to 1 stud + + + QAction::MenuRole::NoRole + + + + + true + + + + assets/icons/editor/snap05.pngassets/icons/editor/snap05.png + + + 1/2-Stud Snapping + + + Set grid snapping to 1/2 studs + + + QAction::MenuRole::NoRole + + + + + true + + + + assets/icons/editor/snapoff.pngassets/icons/editor/snapoff.png + + + No Grid Snapping + + + Turn grid snapping off + + + QAction::MenuRole::NoRole + +