feat: grid snapping wrt/ scaling and moving
This commit is contained in:
parent
32964df4c3
commit
4bfca68fb0
BIN
assets/icons/editor/snap05.png
Normal file
BIN
assets/icons/editor/snap05.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 868 B |
BIN
assets/icons/editor/snap1.png
Normal file
BIN
assets/icons/editor/snap1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 836 B |
BIN
assets/icons/editor/snapoff.png
Normal file
BIN
assets/icons/editor/snapoff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 865 B |
|
@ -2,10 +2,12 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <glm/common.hpp>
|
||||||
#include <glm/ext/matrix_projection.hpp>
|
#include <glm/ext/matrix_projection.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/geometric.hpp>
|
#include <glm/geometric.hpp>
|
||||||
|
#include <glm/gtc/round.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -14,6 +16,7 @@
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "editorcommon.h"
|
#include "editorcommon.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "objects/handles.h"
|
#include "objects/handles.h"
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
#include "qcursor.h"
|
#include "qcursor.h"
|
||||||
|
@ -166,16 +169,28 @@ void MainGLWidget::handleHandleDrag(QMouseEvent* evt) {
|
||||||
glm::vec3 handlePoint, rb;
|
glm::vec3 handlePoint, rb;
|
||||||
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
||||||
|
|
||||||
if (selectedTool == SelectedTool::MOVE)
|
if (selectedTool == SelectedTool::MOVE) {
|
||||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint);
|
glm::vec3 newPos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
||||||
else if (selectedTool == SelectedTool::SCALE) {
|
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();
|
glm::vec3 handlePos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
||||||
|
|
||||||
// Find change in handles, and negate difference in sign between axes
|
// Find change in handles, and negate difference in sign between axes
|
||||||
glm::vec3 diff = handlePos - glm::vec3(editorToolHandles->adornee->lock()->position());
|
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);
|
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))
|
if (!(evt->modifiers() & Qt::ControlModifier))
|
||||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe + (diff / 2.0f);
|
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) {
|
void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) {
|
||||||
if (evt->key() == Qt::Key_W || evt->key() == Qt::Key_S) moveZ = 0;
|
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;
|
else if (evt->key() == Qt::Key_A || evt->key() == Qt::Key_D) moveX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow* MainGLWidget::mainWindow() {
|
||||||
|
return dynamic_cast<MainWindow*>(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;
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef MAINGLWIDGET_H
|
#ifndef MAINGLWIDGET_H
|
||||||
#define MAINGLWIDGET_H
|
#define MAINGLWIDGET_H
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "objects/part.h"
|
#include "objects/part.h"
|
||||||
#include "qevent.h"
|
#include "qevent.h"
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
@ -31,6 +32,9 @@ protected:
|
||||||
void mouseReleaseEvent(QMouseEvent* evt) override;
|
void mouseReleaseEvent(QMouseEvent* evt) override;
|
||||||
void keyPressEvent(QKeyEvent* evt) override;
|
void keyPressEvent(QKeyEvent* evt) override;
|
||||||
void keyReleaseEvent(QKeyEvent* evt) override;
|
void keyReleaseEvent(QKeyEvent* evt) override;
|
||||||
|
|
||||||
|
MainWindow* mainWindow();
|
||||||
|
float snappingFactor();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINGLWIDGET_H
|
#endif // MAINGLWIDGET_H
|
||||||
|
|
|
@ -40,11 +40,18 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
ConnectSelectionChangeHandler();
|
ConnectSelectionChangeHandler();
|
||||||
|
|
||||||
connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = 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; updateSelectedTool(); });
|
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; updateSelectedTool(); });
|
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; updateSelectedTool(); });
|
connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateToolbars(); });
|
||||||
ui->actionToolSelect->setChecked(true);
|
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, [&]() {
|
connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() {
|
||||||
simulationPlaying = !simulationPlaying;
|
simulationPlaying = !simulationPlaying;
|
||||||
|
@ -80,7 +87,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||||
updateSelectedTool();
|
updateToolbars();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ui->explorerView->Init(ui);
|
// ui->explorerView->Init(ui);
|
||||||
|
@ -134,12 +141,16 @@ void MainWindow::timerEvent(QTimerEvent* evt) {
|
||||||
ui->mainWidget->updateCycle();
|
ui->mainWidget->updateCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateSelectedTool() {
|
void MainWindow::updateToolbars() {
|
||||||
ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT);
|
ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT);
|
||||||
ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE);
|
ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE);
|
||||||
ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE);
|
ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE);
|
||||||
ui->actionToolRotate->setChecked(selectedTool == SelectedTool::ROTATE);
|
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::MOVE) editorToolHandles->worldMode = true;
|
||||||
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
enum GridSnappingMode {
|
||||||
|
SNAP_1_STUD,
|
||||||
|
SNAP_05_STUDS,
|
||||||
|
SNAP_OFF,
|
||||||
|
};
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
|
@ -22,11 +28,13 @@ public:
|
||||||
MainWindow(QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
|
GridSnappingMode snappingMode;
|
||||||
|
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
private:
|
private:
|
||||||
QBasicTimer timer;
|
QBasicTimer timer;
|
||||||
|
|
||||||
void updateSelectedTool();
|
void updateToolbars();
|
||||||
void timerEvent(QTimerEvent*) override;
|
void timerEvent(QTimerEvent*) override;
|
||||||
void ConnectSelectionChangeHandler();
|
void ConnectSelectionChangeHandler();
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1027</width>
|
<width>1027</width>
|
||||||
<height>29</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
@ -115,6 +115,10 @@
|
||||||
<addaction name="actionToolScale"/>
|
<addaction name="actionToolScale"/>
|
||||||
<addaction name="actionToolRotate"/>
|
<addaction name="actionToolRotate"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionGridSnap1"/>
|
||||||
|
<addaction name="actionGridSnap05"/>
|
||||||
|
<addaction name="actionGridSnapOff"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="actionToggleSimulation"/>
|
<addaction name="actionToggleSimulation"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="actionAddPart">
|
<action name="actionAddPart">
|
||||||
|
@ -257,6 +261,60 @@
|
||||||
<string>F5</string>
|
<string>F5</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionGridSnap1">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>assets/icons/editor/snap1.png</normaloff>assets/icons/editor/snap1.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1-Stud Snapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set grid snapping to 1 stud</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::MenuRole::NoRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGridSnap05">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>assets/icons/editor/snap05.png</normaloff>assets/icons/editor/snap05.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1/2-Stud Snapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set grid snapping to 1/2 studs</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::MenuRole::NoRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGridSnapOff">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>assets/icons/editor/snapoff.png</normaloff>assets/icons/editor/snapoff.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>No Grid Snapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Turn grid snapping off</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::MenuRole::NoRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
Loading…
Reference in a new issue