Compare commits

...

4 commits

15 changed files with 237 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

View file

@ -25,8 +25,10 @@ set(PROJECT_SOURCES
mainwindow.ui
mainglwidget.h
mainglwidget.cpp
explorermodel.h
explorermodel.cpp
panes/explorerview.h
panes/explorerview.cpp
panes/explorermodel.h
panes/explorermodel.cpp
${TS_FILES}
)

View file

@ -10,14 +10,11 @@
#include <QWidget>
#include <QTreeView>
#include <QAbstractItemView>
#include <memory>
#include "common.h"
#include "physics/simulation.h"
#include "objects/part.h"
#include "explorermodel.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "qobject.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -27,8 +24,7 @@ MainWindow::MainWindow(QWidget *parent)
timer.start(33, this);
setMouseTracking(true);
ui->explorerView->setModel(new ExplorerModel(std::dynamic_pointer_cast<Instance>(workspace)));
ui->explorerView->setRootIsDecorated(false);
// ui->explorerView->Init(ui);
simulationInit();
@ -44,6 +40,7 @@ MainWindow::MainWindow(QWidget *parent)
},
.anchored = true,
}));
ui->mainWidget->lastPart->name = "Baseplate";
syncPartPhysics(ui->mainWidget->lastPart);
workspace->AddChild(ui->mainWidget->lastPart = Part::New({

View file

@ -1,8 +1,10 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "panes/explorerview.h"
#include "qbasictimer.h"
#include "qcoreevent.h"
#include "qmenu.h"
#include <QMainWindow>
#include <QLineEdit>
@ -20,8 +22,8 @@ public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private:
QBasicTimer timer;
void timerEvent(QTimerEvent*) override;

View file

@ -44,6 +44,18 @@
<height>29</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="explorerWidget">
@ -56,7 +68,7 @@
<widget class="QWidget" name="dockWidgetContents">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="explorerView"/>
<widget class="ExplorerView" name="explorerView"/>
</item>
</layout>
</widget>
@ -68,6 +80,11 @@
<extends>QOpenGLWidget</extends>
<header>mainglwidget.h</header>
</customwidget>
<customwidget>
<class>ExplorerView</class>
<extends>QTreeView</extends>
<header>panes/explorerview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View file

@ -1,13 +1,14 @@
#include "explorermodel.h"
#include "objects/base/instance.h"
#include "qabstractitemmodel.h"
#include "qcontainerfwd.h"
#include "qicon.h"
#include "qimage.h"
#include "qnamespace.h"
#include "qobject.h"
#include "qwidget.h"
#include "common.h"
#include <algorithm>
#include <cstdio>
#include <optional>
#include "objects/base/instance.h"
@ -116,6 +117,14 @@ QVariant ExplorerModel::data(const QModelIndex &index, int role) const {
return {};
}
bool ExplorerModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (!index.isValid() || role != Qt::EditRole) return false;
Instance* inst = static_cast<Instance*>(index.internalPointer());
inst->name = value.toString().toStdString();
return true;
}
QVariant ExplorerModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
@ -124,8 +133,11 @@ QVariant ExplorerModel::headerData(int section, Qt::Orientation orientation,
Qt::ItemFlags ExplorerModel::flags(const QModelIndex &index) const
{
//return index.isValid()
// ? QAbstractItemModel::flags(index) : Qt::ItemFlags(Qt::NoItemFlags);
return index.isValid()
? QAbstractItemModel::flags(index) : Qt::ItemFlags(Qt::NoItemFlags);
? QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled
: Qt::NoItemFlags | Qt::ItemIsDropEnabled;
}
QImage ExplorerModel::iconOf(InstanceType* type) const {
@ -137,4 +149,55 @@ QImage ExplorerModel::iconOf(InstanceType* type) const {
QImage icon("assets/icons/" + QString::fromStdString(currentClass->explorerIcon));
instanceIconCache[type->className] = icon;
return icon;
}
bool ExplorerModel::moveRows(const QModelIndex &sourceParentIdx, int sourceRow, int count, const QModelIndex &destinationParentIdx, int destinationChild) {
Instance* sourceParent = sourceParentIdx.isValid() ? static_cast<Instance*>(sourceParentIdx.internalPointer()) : workspace.get();
Instance* destinationParent = destinationParentIdx.isValid() ? static_cast<Instance*>(destinationParentIdx.internalPointer()) : workspace.get();
printf("Moved %d from %s\n", count, sourceParent->name.c_str());
if ((sourceRow + count) >= sourceParent->GetChildren().size()) {
fprintf(stderr, "Attempt to move rows %d-%d from %s (%s) while it only has %zu children.\n", sourceRow, sourceRow + count, sourceParent->name.c_str(), sourceParent->GetClass()->className.c_str(), sourceParent->GetChildren().size());
return false;
}
for (int i = sourceRow; i < (sourceRow + count); i++) {
sourceParent->GetChildren()[i]->SetParent(destinationParent->shared_from_this());
}
return true;
}
bool ExplorerModel::removeRows(int row, int count, const QModelIndex& parentIdx) {
Instance* parent = parentIdx.isValid() ? static_cast<Instance*>(parentIdx.internalPointer()) : workspace.get();
for (int i = row; i < (row + count); i++) {
//parent->GetChildren()[i]->SetParent(nullptr);
}
return true;
}
bool ExplorerModel::insertRows(int row, int count, const QModelIndex & parentIdx) {
//Instance* parent = parentIdx.isValid() ? static_cast<Instance*>(parentIdx.internalPointer()) : workspace.get();
//beginInsertRows(parentIdx, parent->GetChildren().size(), parent->GetChildren().size() + count);
//for ()
//endInsertRows();
//return true;
return false;
}
Qt::DropActions ExplorerModel::supportedDragActions() const {
return Qt::DropAction::MoveAction;
}
Qt::DropActions ExplorerModel::supportedDropActions() const {
return Qt::DropAction::MoveAction;
}
InstanceRef ExplorerModel::fromIndex(const QModelIndex index) {
if (!index.isValid()) return workspace;
return static_cast<Instance*>(index.internalPointer())->shared_from_this();
}

View file

@ -1,14 +1,19 @@
#ifndef EXPLORERMODEL_H
#define EXPLORERMODEL_H
#pragma once
#include "objects/base/instance.h"
#include "objects/part.h"
#include "qabstractitemmodel.h"
#include "qevent.h"
#include "qmenu.h"
#include "qnamespace.h"
#include "qtreeview.h"
#include <QOpenGLWidget>
#include <QWidget>
#include <memory>
// #ifndef EXPLORERMODEL_H
// #define EXPLORERMODEL_H
class ExplorerModel : public QAbstractItemModel {
Q_OBJECT
public:
@ -18,6 +23,7 @@ public:
~ExplorerModel() override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
@ -26,11 +32,16 @@ public:
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = {}) const override;
int columnCount(const QModelIndex &parent = {}) const override;
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()) override;
bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex()) override;
Qt::DropActions supportedDragActions() const override;
Qt::DropActions supportedDropActions() const override;
InstanceRef fromIndex(const QModelIndex index);
private:
InstanceRef rootItem;
QModelIndex toIndex(InstanceRef item);
QImage iconOf(InstanceType* type) const;
};
#endif // EXPLORERMODEL_H
// #endif

View file

@ -0,0 +1,49 @@
#include "explorerview.h"
#include "explorermodel.h"
#include "common.h"
#include "qaction.h"
#include "qnamespace.h"
ExplorerView::ExplorerView(QWidget* parent):
QTreeView(parent),
model(ExplorerModel(std::dynamic_pointer_cast<Instance>(workspace))) {
this->setModel(&model);
this->setRootIsDecorated(false);
this->setDragDropMode(QAbstractItemView::InternalMove);
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
this->setDragEnabled(true);
this->setAcceptDrops(true);
this->setDropIndicatorShown(true);
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QTreeView::customContextMenuRequested, this, [&](const QPoint& point) {
QModelIndex index = this->indexAt(point);
contextMenu.exec(this->viewport()->mapToGlobal(point));
});
buildContextMenu();
}
ExplorerView::~ExplorerView() {
}
void ExplorerView::keyPressEvent(QKeyEvent* event) {
switch (event->key()) {
case Qt::Key_Delete:
actionDelete->trigger();
break;
}
}
void ExplorerView::buildContextMenu() {
// This will leak memory. Anyway...
contextMenu.addAction(this->actionDelete = new QAction(QIcon("assets/icons/editor/delete"), "Delete"));
connect(actionDelete, &QAction::triggered, this, [&]() {
QModelIndexList selectedIndexes = this->selectionModel()->selectedIndexes();
for (QModelIndex index : selectedIndexes) {
model.fromIndex(index)->SetParent(std::nullopt);
}
});
}

View file

@ -0,0 +1,35 @@
#pragma once
#include "objects/base/instance.h"
#include "objects/part.h"
#include "qevent.h"
#include "qmenu.h"
#include "qnamespace.h"
#include "qtreeview.h"
#include <QOpenGLWidget>
#include <QWidget>
#include <memory>
#include "explorermodel.h"
class Ui_MainWindow;
class ExplorerView : public QTreeView {
public:
ExplorerView(QWidget* parent = nullptr);
~ExplorerView() override;
void keyPressEvent(QKeyEvent* evt) override;
private:
ExplorerModel model;
QMenu contextMenu;
// TODO: Move these to a separate top-level namespace so these can be
// accessed from multiple locations
QAction* actionDelete;
QAction* actionCopy;
QAction* actionCut;
QAction* actionPaste;
QAction* actionPasteInto;
QAction* actionSelectChildren;
void buildContextMenu();
};

8
run.sh
View file

@ -1 +1,7 @@
cmake . && cmake --build . && ./bin/$1
[ "$2" = "-debug" ] && CMAKE_OPTS=-DCMAKE_BUILD_TYPE=Debug
[ "$2" = "-release" ] && CMAKE_OPTS=-DCMAKE_BUILD_TYPE=Release
[ "$2" = "-reldbg" ] && CMAKE_OPTS=-DCMAKE_BUILD_TYPE=RelWithDebInfo
[ "$3" = "-gdb" ] && PRE_COMMAND="gdb -ex run "
cmake $CMAKE_OPTS . && cmake --build . && $PRE_COMMAND ./bin/$1

View file

@ -42,10 +42,17 @@ void Instance::SetParent(std::optional<std::shared_ptr<Instance>> newParent) {
// TODO: Add code for sending signals for parent updates
// TODO: Yeahhh maybe this isn't the best way of doing this?
if (hierarchyPostUpdateHandler.has_value()) hierarchyPostUpdateHandler.value()(this->shared_from_this(), lastParent, newParent);
this->OnParentUpdated(lastParent, newParent);
}
std::optional<std::shared_ptr<Instance>> Instance::GetParent() {
if (!parent.has_value()) return std::nullopt;
if (parent.value().expired()) return std::nullopt;
return parent.value().lock();
}
void Instance::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
// Empty stub
}

View file

@ -2,6 +2,7 @@
#include "metadata.h"
#include <memory>
#include <optional>
#include <string>
// Struct describing information about an instance
@ -23,6 +24,8 @@ private:
protected:
Instance(InstanceType*);
virtual ~Instance();
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
public:
static InstanceType* TYPE;
std::string name;

View file

@ -19,4 +19,19 @@ Part::Part(): Instance(&TYPE_) {
Part::Part(PartConstructParams params): Instance(&TYPE_), position(params.position), rotation(params.rotation),
scale(params.scale), material(params.material), anchored(params.anchored) {
}
// This feels wrong. Get access to PhysicsWorld somehow else? Part will need access to this often though, most likely...
extern rp::PhysicsWorld* world;
Part::~Part() {
world->destroyRigidBody(rigidBody);
Instance::~Instance();
}
void Part::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
if (this->rigidBody)
this->rigidBody->setIsActive(newParent.has_value());
// TODO: Sleeping bodies that touch this one also need to be updated
}

View file

@ -20,6 +20,8 @@ struct PartConstructParams {
};
class Part : public Instance {
protected:
void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override;
public:
static InstanceType* TYPE;
@ -34,6 +36,7 @@ public:
Part();
Part(PartConstructParams params);
~Part() override;
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); };
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };

View file

@ -5,6 +5,7 @@
#include <reactphysics3d/collision/shapes/BoxShape.h>
#include <reactphysics3d/collision/shapes/CollisionShape.h>
#include <reactphysics3d/components/RigidBodyComponents.h>
#include <reactphysics3d/engine/EventListener.h>
#include <reactphysics3d/mathematics/Quaternion.h>
#include <reactphysics3d/mathematics/Transform.h>
#include <reactphysics3d/mathematics/Vector3.h>
@ -19,8 +20,15 @@
namespace rp = reactphysics3d;
class PhysicsListener : public rp::EventListener {
void onContact(const CollisionCallback::CallbackData& /*callbackData*/) override {
// printf("Collision occurred!\n");
}
};
rp::PhysicsCommon physicsCommon;
rp::PhysicsWorld* world;
PhysicsListener eventListener;
void simulationInit() {
world = physicsCommon.createPhysicsWorld();
@ -47,6 +55,8 @@ void syncPartPhysics(std::shared_ptr<Part> part) {
if (part->rigidBody->getNbColliders() == 0)
part->rigidBody->addCollider(shape, rp::Transform());
part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC);
world->setEventListener(&eventListener);
}
void physicsStep(float deltaTime) {