diff --git a/core/src/objects/model.cpp b/core/src/objects/model.cpp index 1354ad6..86ca693 100644 --- a/core/src/objects/model.cpp +++ b/core/src/objects/model.cpp @@ -1,4 +1,4 @@ #include "model.h" -Model::Model(): Instance(&TYPE) {} +Model::Model(): PVInstance(&TYPE) {} Model::~Model() = default; \ No newline at end of file diff --git a/core/src/objects/model.h b/core/src/objects/model.h index 4e9381c..4e40a07 100644 --- a/core/src/objects/model.h +++ b/core/src/objects/model.h @@ -2,11 +2,12 @@ #include "objects/annotation.h" #include "objects/base/instance.h" +#include "objects/pvinstance.h" #include // Group object for Parts -class DEF_INST_(explorer_icon="model") Model : public Instance { +class DEF_INST_(explorer_icon="model") Model : public PVInstance { AUTOGEN_PREAMBLE public: diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 9e416af..61f3227 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -22,7 +22,7 @@ Part::Part(): Part(PartConstructParams { .size = glm::vec3(2, 1.2, 4), .color = Color3(0.639216f, 0.635294f, 0.647059f) }) { } -Part::Part(PartConstructParams params): Instance(&TYPE), cframe(CFrame::FromEulerAnglesXYZ((Vector3)params.rotation) + params.position), +Part::Part(PartConstructParams params): PVInstance(&TYPE), cframe(CFrame::FromEulerAnglesXYZ((Vector3)params.rotation) + params.position), size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) { } diff --git a/core/src/objects/part.h b/core/src/objects/part.h index a6ed681..8db8a14 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -13,6 +13,7 @@ #include #include #include "annotation.h" +#include "objects/pvinstance.h" namespace rp = reactphysics3d; @@ -29,7 +30,7 @@ struct PartConstructParams { class Workspace; -class DEF_INST_(explorer_icon="part") Part : public Instance { +class DEF_INST_(explorer_icon="part") Part : public PVInstance { AUTOGEN_PREAMBLE protected: // Joints where this part is Part0 diff --git a/core/src/objects/pvinstance.cpp b/core/src/objects/pvinstance.cpp new file mode 100644 index 0000000..c3636c1 --- /dev/null +++ b/core/src/objects/pvinstance.cpp @@ -0,0 +1,4 @@ +#include "pvinstance.h" + +PVInstance::PVInstance(const InstanceType* type): Instance(type) {} +PVInstance::~PVInstance() = default; \ No newline at end of file diff --git a/core/src/objects/pvinstance.h b/core/src/objects/pvinstance.h new file mode 100644 index 0000000..1a97304 --- /dev/null +++ b/core/src/objects/pvinstance.h @@ -0,0 +1,13 @@ +#pragma once + +#include "objects/annotation.h" +#include "objects/base/instance.h" + +class DEF_INST_ABSTRACT PVInstance : public Instance { + AUTOGEN_PREAMBLE + +protected: + PVInstance(const InstanceType*); +public: + ~PVInstance(); +}; \ No newline at end of file diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index 3f068e2..95c9dc5 100755 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include "common.h" #include "math_helper.h" #include "objects/base/instance.h" +#include "objects/pvinstance.h" #include "partassembly.h" #include "physics/util.h" #include "rendering/renderer.h" @@ -390,6 +392,17 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) { if (!rayHit || !partFromBody(rayHit->body)) { setSelection({}); return; } std::shared_ptr part = partFromBody(rayHit->body); if (part->locked) { setSelection({}); return; } + + std::shared_ptr selObject = part; + + // Traverse to the root model + if (~evt->modifiers() & Qt::AltModifier) { + std::optional> nextParent = selObject->GetParent(); + while (nextParent.value() && nextParent.value()->IsA("Model")) { + selObject = std::dynamic_pointer_cast(nextParent.value()); nextParent = selObject->GetParent(); + } + } + initialFrame = part->cframe; initialHitPos = rayHit->worldPoint; initialHitNormal = rayHit->worldNormal; @@ -419,20 +432,20 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) { //part.selected = true; isMouseDragging = true; draggingObject = part; - if (evt->modifiers() & Qt::ControlModifier) { + if (evt->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier)) { std::vector> currentSelection = getSelection(); for (size_t i = 0; i < currentSelection.size(); i++) { std::shared_ptr inst = currentSelection[i]; - if (inst == part) { + if (inst == selObject) { currentSelection.erase(currentSelection.begin() + i); goto skipAddPart; } } - currentSelection.push_back(part); + currentSelection.push_back(selObject); skipAddPart: setSelection(currentSelection); } else - setSelection({ part }); + setSelection({ selObject }); // Disable bit so that we can ignore the part while raycasting // part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index 5ca02b3..0369fc4 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,13 @@ void logQtMessage(QtMsgType type, const QMessageLogContext &context, const QStri // if (defaultMessageHandler) defaultMessageHandler(type, context, msg); } +inline void playSound(QString path) { + QSoundEffect *sound = new QSoundEffect; + sound->setSource(QUrl::fromLocalFile(path)); + sound->play(); + sound->connect(sound, &QSoundEffect::playingChanged, [=]() { /* Thank you QSound source code! */ sound->deleteLater(); return false; }); +} + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) @@ -383,6 +391,7 @@ void MainWindow::connectActionHandlers() { model->SetParent(firstParent); setSelection({ model }); + playSound("./assets/excluded/electronicpingshort.wav"); }); connect(ui->actionUngroupObjects, &QAction::triggered, this, [&]() { @@ -401,6 +410,7 @@ void MainWindow::connectActionHandlers() { } setSelection(newSelection); + playSound("./assets/excluded/electronicpingshort.wav"); }); connect(ui->actionSaveModel, &QAction::triggered, this, [&]() {