Compare commits

...

4 commits

20 changed files with 119 additions and 52 deletions

View file

@ -41,11 +41,12 @@ int main() {
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glewInit(); glewInit();
dataModel->Init();
simulationInit(); simulationInit();
renderInit(window, 1200, 900); renderInit(window, 1200, 900);
// Baseplate // Baseplate
workspace->AddChild(Part::New({ workspace()->AddChild(Part::New({
.position = glm::vec3(0, -5, 0), .position = glm::vec3(0, -5, 0),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(512, 1.2, 512), .scale = glm::vec3(512, 1.2, 512),
@ -57,7 +58,7 @@ int main() {
.anchored = true, .anchored = true,
})); }));
workspace->AddChild(lastPart = Part::New({ workspace()->AddChild(lastPart = Part::New({
.position = glm::vec3(0), .position = glm::vec3(0),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(4, 1.2, 2), .scale = glm::vec3(4, 1.2, 2),
@ -68,7 +69,7 @@ int main() {
} }
})); }));
for (InstanceRef inst : workspace->GetChildren()) { for (InstanceRef inst : workspace()->GetChildren()) {
if (inst->GetClass()->className != "Part") continue; if (inst->GetClass()->className != "Part") continue;
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst); std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
syncPartPhysics(part); syncPartPhysics(part);
@ -161,7 +162,7 @@ void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_F && action == GLFW_PRESS) { if (key == GLFW_KEY_F && action == GLFW_PRESS) {
workspace->AddChild(lastPart = Part::New({ workspace()->AddChild(lastPart = Part::New({
.position = camera.cameraPos + camera.cameraFront * glm::vec3(3), .position = camera.cameraPos + camera.cameraFront * glm::vec3(3),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(1, 1, 1), .scale = glm::vec3(1, 1, 1),

View file

@ -153,7 +153,7 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) {
else if (evt->key() == Qt::Key_D) moveX = -1; else if (evt->key() == Qt::Key_D) moveX = -1;
if (evt->key() == Qt::Key_F) { if (evt->key() == Qt::Key_F) {
workspace->AddChild(lastPart = Part::New({ workspace()->AddChild(lastPart = Part::New({
.position = camera.cameraPos + camera.cameraFront * glm::vec3(3), .position = camera.cameraPos + camera.cameraFront * glm::vec3(3),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(1, 1, 1), .scale = glm::vec3(1, 1, 1),

View file

@ -18,6 +18,7 @@
#include "objects/part.h" #include "objects/part.h"
#include "qitemselectionmodel.h" #include "qitemselectionmodel.h"
#include "qobject.h" #include "qobject.h"
#include "qsysinfo.h"
SelectedTool selectedTool; SelectedTool selectedTool;
@ -25,6 +26,8 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
dataModel->Init();
ui->setupUi(this); ui->setupUi(this);
timer.start(33, this); timer.start(33, this);
setMouseTracking(true); setMouseTracking(true);
@ -49,7 +52,7 @@ MainWindow::MainWindow(QWidget *parent)
simulationInit(); simulationInit();
// Baseplate // Baseplate
workspace->AddChild(ui->mainWidget->lastPart = Part::New({ workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0, -5, 0), .position = glm::vec3(0, -5, 0),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(512, 1.2, 512), .scale = glm::vec3(512, 1.2, 512),
@ -63,7 +66,7 @@ MainWindow::MainWindow(QWidget *parent)
ui->mainWidget->lastPart->name = "Baseplate"; ui->mainWidget->lastPart->name = "Baseplate";
syncPartPhysics(ui->mainWidget->lastPart); syncPartPhysics(ui->mainWidget->lastPart);
workspace->AddChild(ui->mainWidget->lastPart = Part::New({ workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0), .position = glm::vec3(0),
.rotation = glm::vec3(0), .rotation = glm::vec3(0),
.scale = glm::vec3(4, 1.2, 2), .scale = glm::vec3(4, 1.2, 2),

View file

@ -60,7 +60,7 @@ QModelIndex ExplorerModel::index(int row, int column, const QModelIndex &parent)
} }
QModelIndex ExplorerModel::toIndex(InstanceRef item) { QModelIndex ExplorerModel::toIndex(InstanceRef item) {
if (item == rootItem) if (item == rootItem || !item->GetParent().has_value())
return {}; return {};
InstanceRef parentItem = item->GetParent().value(); InstanceRef parentItem = item->GetParent().value();
@ -148,10 +148,10 @@ Qt::ItemFlags ExplorerModel::flags(const QModelIndex &index) const
: Qt::NoItemFlags | Qt::ItemIsDropEnabled; : Qt::NoItemFlags | Qt::ItemIsDropEnabled;
} }
QImage ExplorerModel::iconOf(InstanceType* type) const { QImage ExplorerModel::iconOf(const InstanceType* type) const {
if (instanceIconCache.count(type->className)) return instanceIconCache[type->className]; if (instanceIconCache.count(type->className)) return instanceIconCache[type->className];
InstanceType* currentClass = type; const InstanceType* currentClass = type;
while (currentClass->explorerIcon.empty()) currentClass = currentClass->super; while (currentClass->explorerIcon.empty()) currentClass = currentClass->super;
QImage icon("assets/icons/" + QString::fromStdString(currentClass->explorerIcon)); QImage icon("assets/icons/" + QString::fromStdString(currentClass->explorerIcon));
@ -160,8 +160,8 @@ QImage ExplorerModel::iconOf(InstanceType* type) const {
} }
bool ExplorerModel::moveRows(const QModelIndex &sourceParentIdx, int sourceRow, int count, const QModelIndex &destinationParentIdx, int destinationChild) { 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* sourceParent = sourceParentIdx.isValid() ? static_cast<Instance*>(sourceParentIdx.internalPointer()) : rootItem.get();
Instance* destinationParent = destinationParentIdx.isValid() ? static_cast<Instance*>(destinationParentIdx.internalPointer()) : workspace.get(); Instance* destinationParent = destinationParentIdx.isValid() ? static_cast<Instance*>(destinationParentIdx.internalPointer()) : rootItem.get();
printf("Moved %d from %s\n", count, sourceParent->name.c_str()); printf("Moved %d from %s\n", count, sourceParent->name.c_str());
@ -178,7 +178,7 @@ bool ExplorerModel::moveRows(const QModelIndex &sourceParentIdx, int sourceRow,
} }
bool ExplorerModel::removeRows(int row, int count, const QModelIndex& parentIdx) { bool ExplorerModel::removeRows(int row, int count, const QModelIndex& parentIdx) {
Instance* parent = parentIdx.isValid() ? static_cast<Instance*>(parentIdx.internalPointer()) : workspace.get(); Instance* parent = parentIdx.isValid() ? static_cast<Instance*>(parentIdx.internalPointer()) : rootItem.get();
for (int i = row; i < (row + count); i++) { for (int i = row; i < (row + count); i++) {
//parent->GetChildren()[i]->SetParent(nullptr); //parent->GetChildren()[i]->SetParent(nullptr);
@ -206,7 +206,7 @@ Qt::DropActions ExplorerModel::supportedDropActions() const {
InstanceRef ExplorerModel::fromIndex(const QModelIndex index) const { InstanceRef ExplorerModel::fromIndex(const QModelIndex index) const {
if (!index.isValid()) return workspace; if (!index.isValid()) return rootItem;
return static_cast<Instance*>(index.internalPointer())->shared_from_this(); return static_cast<Instance*>(index.internalPointer())->shared_from_this();
} }

View file

@ -45,7 +45,7 @@ public:
private: private:
InstanceRef rootItem; InstanceRef rootItem;
QModelIndex toIndex(InstanceRef item); QModelIndex toIndex(InstanceRef item);
QImage iconOf(InstanceType* type) const; QImage iconOf(const InstanceType* type) const;
}; };
// #endif // #endif

View file

@ -2,13 +2,14 @@
#include "explorermodel.h" #include "explorermodel.h"
#include "common.h" #include "common.h"
#include "objects/base/instance.h" #include "objects/base/instance.h"
#include "objects/workspace.h"
#include "qabstractitemmodel.h" #include "qabstractitemmodel.h"
#include "qaction.h" #include "qaction.h"
#include "qnamespace.h" #include "qnamespace.h"
ExplorerView::ExplorerView(QWidget* parent): ExplorerView::ExplorerView(QWidget* parent):
QTreeView(parent), QTreeView(parent),
model(ExplorerModel(std::dynamic_pointer_cast<Instance>(workspace))) { model(ExplorerModel(std::dynamic_pointer_cast<Instance>(dataModel))) {
this->setModel(&model); this->setModel(&model);
// Disabling the root decoration will cause the expand/collapse chevrons to be hidden too, we don't want that // Disabling the root decoration will cause the expand/collapse chevrons to be hidden too, we don't want that
@ -23,6 +24,9 @@ ExplorerView::ExplorerView(QWidget* parent):
this->setDropIndicatorShown(true); this->setDropIndicatorShown(true);
this->setContextMenuPolicy(Qt::CustomContextMenu); this->setContextMenuPolicy(Qt::CustomContextMenu);
// Expand workspace
this->expand(model.ObjectToIndex(workspace()));
connect(this, &QTreeView::customContextMenuRequested, this, [&](const QPoint& point) { connect(this, &QTreeView::customContextMenuRequested, this, [&](const QPoint& point) {
QModelIndex index = this->indexAt(point); QModelIndex index = this->indexAt(point);
contextMenu.exec(this->viewport()->mapToGlobal(point)); contextMenu.exec(this->viewport()->mapToGlobal(point));

View file

@ -5,7 +5,7 @@
Camera camera(glm::vec3(0.0, 0.0, 3.0)); Camera camera(glm::vec3(0.0, 0.0, 3.0));
//std::vector<Part> parts; //std::vector<Part> parts;
std::shared_ptr<Workspace> workspace = Workspace::New(); std::shared_ptr<DataModel> dataModel = DataModel::New();
std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler; std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler; std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;

View file

@ -14,7 +14,8 @@ typedef std::function<void(std::vector<InstanceRefWeak> oldSelection, std::vecto
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS // TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
extern Camera camera; extern Camera camera;
extern std::shared_ptr<Workspace> workspace; extern std::shared_ptr<DataModel> dataModel;
inline std::shared_ptr<Workspace> workspace() { return dataModel->workspace; }
extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler; extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler; extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;

View file

@ -10,21 +10,19 @@
#include <optional> #include <optional>
// Static so that this variable name is "local" to this source file // Static so that this variable name is "local" to this source file
static InstanceType TYPE_ { const InstanceType Instance::TYPE = {
.super = NULL, .super = NULL,
.className = "Instance", .className = "Instance",
.constructor = NULL, // Instance is abstract and therefore not creatable .constructor = NULL, // Instance is abstract and therefore not creatable
.explorerIcon = "instance", .explorerIcon = "instance",
}; };
InstanceType* Instance::TYPE = &TYPE_;
// Instance is abstract, so it should not implement GetClass directly // Instance is abstract, so it should not implement GetClass directly
// InstanceType* Instance::GetClass() { // InstanceType* Instance::GetClass() {
// return &TYPE_; // return &TYPE_;
// } // }
Instance::Instance(InstanceType* type) { Instance::Instance(const InstanceType* type) {
this->name = type->className; this->name = type->className;
this->memberMap = std::make_unique<MemberMap>( MemberMap { this->memberMap = std::make_unique<MemberMap>( MemberMap {
@ -48,7 +46,7 @@ bool Instance::ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>>
} }
bool Instance::SetParent(std::optional<std::shared_ptr<Instance>> newParent) { bool Instance::SetParent(std::optional<std::shared_ptr<Instance>> newParent) {
if (!ancestryContinuityCheck(newParent)) if (this->parentLocked || !ancestryContinuityCheck(newParent))
return false; return false;
auto lastParent = GetParent(); auto lastParent = GetParent();

View file

@ -19,7 +19,7 @@ typedef std::shared_ptr<Instance>(*InstanceConstructor)();
// Struct describing information about an instance // Struct describing information about an instance
struct InstanceType { struct InstanceType {
InstanceType* super; // May be null const InstanceType* super; // May be null
std::string className; std::string className;
InstanceConstructor constructor; InstanceConstructor constructor;
std::string explorerIcon = ""; std::string explorerIcon = "";
@ -38,18 +38,21 @@ private:
bool ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent); bool ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent);
protected: protected:
bool parentLocked = false;
std::unique_ptr<MemberMap> memberMap; std::unique_ptr<MemberMap> memberMap;
Instance(InstanceType*); Instance(const InstanceType*);
virtual ~Instance(); virtual ~Instance();
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent); virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
template <typename T> inline std::shared_ptr<T> shared() { return std::dynamic_pointer_cast<T>(this->shared_from_this()); }
public: public:
static InstanceType* TYPE; const static InstanceType TYPE;
std::string name; std::string name;
// Instance is abstract, so it should not implement GetClass directly // Instance is abstract, so it should not implement GetClass directly
virtual InstanceType* GetClass() = 0; virtual const InstanceType* GetClass() = 0;
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent); bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);
std::optional<std::shared_ptr<Instance>> GetParent(); std::optional<std::shared_ptr<Instance>> GetParent();
inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; } inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; }

View file

@ -0,0 +1,4 @@
#include "service.h"
#include <memory>
Service::Service(std::weak_ptr<DataModel> root) : dataModel(root) {}

View file

@ -0,0 +1,12 @@
#pragma once
// Services are top-level singletons and belong to a specific DataModel
// They serve one specific task and can be accessed using game:GetService
#include "objects/datamodel.h"
#include <memory>
class Service {
protected:
std::weak_ptr<DataModel> dataModel;
Service(std::weak_ptr<DataModel> root);
};

22
src/objects/datamodel.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "datamodel.h"
#include "workspace.h"
#include <memory>
const InstanceType DataModel::TYPE = {
.super = &Instance::TYPE,
.className = "DataModel",
.constructor = nullptr,
};
const InstanceType* DataModel::GetClass() {
return &TYPE;
}
DataModel::DataModel()
: Instance(&TYPE) {
}
void DataModel::Init() {
this->workspace = std::make_shared<Workspace>(shared<DataModel>());
this->AddChild(this->workspace);
}

21
src/objects/datamodel.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#include "base.h"
#include <memory>
class Workspace;
// The root instance to all objects in the hierarchy
class DataModel : public Instance {
//private:
public:
const static InstanceType TYPE;
std::shared_ptr<Workspace> workspace;
DataModel();
void Init();
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
virtual const InstanceType* GetClass() override;
};

View file

@ -6,23 +6,21 @@
#include <optional> #include <optional>
#include "physics/simulation.h" #include "physics/simulation.h"
static InstanceType TYPE_ { const InstanceType Part::TYPE = {
.super = Instance::TYPE, .super = &Instance::TYPE,
.className = "Part", .className = "Part",
.constructor = &Part::CreateGeneric, .constructor = &Part::CreateGeneric,
.explorerIcon = "part", .explorerIcon = "part",
}; };
InstanceType* Part::TYPE = &TYPE_; const InstanceType* Part::GetClass() {
return &TYPE;
InstanceType* Part::GetClass() {
return &TYPE_;
} }
Part::Part(): Part(PartConstructParams {}) { Part::Part(): Part(PartConstructParams {}) {
} }
Part::Part(PartConstructParams params): Instance(&TYPE_), position(params.position), rotation(params.rotation), Part::Part(PartConstructParams params): Instance(&TYPE), position(params.position), rotation(params.rotation),
scale(params.scale), material(params.material), anchored(params.anchored) { scale(params.scale), material(params.material), anchored(params.anchored) {
this->memberMap = std::make_unique<MemberMap>(MemberMap { this->memberMap = std::make_unique<MemberMap>(MemberMap {
.super = std::move(this->memberMap), .super = std::move(this->memberMap),

View file

@ -24,7 +24,7 @@ protected:
void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override; void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override;
void onUpdated(std::string); void onUpdated(std::string);
public: public:
static InstanceType* TYPE; const static InstanceType TYPE;
// TODO: Switch these over to our dedicated datatypes // TODO: Switch these over to our dedicated datatypes
glm::vec3 position; glm::vec3 position;
@ -43,5 +43,5 @@ public:
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); }; 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); }; static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
static inline InstanceRef CreateGeneric() { return std::make_shared<Part>(); }; static inline InstanceRef CreateGeneric() { return std::make_shared<Part>(); };
virtual InstanceType* GetClass() override; virtual const InstanceType* GetClass() override;
}; };

View file

@ -1,16 +1,15 @@
#include "workspace.h" #include "workspace.h"
static InstanceType TYPE_ { const InstanceType Workspace::TYPE = {
.super = Instance::TYPE, .super = &Instance::TYPE,
.className = "Workspace", .className = "Workspace",
.constructor = &Workspace::Create, // .constructor = &Workspace::Create,
.explorerIcon = "workspace",
}; };
InstanceType* Workspace::TYPE = &TYPE_; const InstanceType* Workspace::GetClass() {
return &TYPE;
InstanceType* Workspace::GetClass() {
return &TYPE_;
} }
Workspace::Workspace(): Instance(&TYPE_) { Workspace::Workspace(std::weak_ptr<DataModel> dataModel): Instance(&TYPE), Service(dataModel) {
} }

View file

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "objects/base/service.h"
#include <memory> #include <memory>
class Workspace : public Instance { class Workspace : public Instance, Service {
//private: //private:
public: public:
static InstanceType* TYPE; const static InstanceType TYPE;
Workspace(); Workspace(std::weak_ptr<DataModel> dataModel);
static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); }; // static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
static inline InstanceRef Create() { return std::make_shared<Workspace>(); }; // static inline InstanceRef Create() { return std::make_shared<Workspace>(); };
virtual InstanceType* GetClass() override; virtual const InstanceType* GetClass() override;
}; };

View file

@ -72,7 +72,7 @@ void physicsStep(float deltaTime) {
// Naive implementation. Parts are only considered so if they are just under Workspace // Naive implementation. Parts are only considered so if they are just under Workspace
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance // TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
for (InstanceRef obj : workspace->GetChildren()) { for (InstanceRef obj : workspace()->GetChildren()) {
if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(obj); std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(obj);
const rp::Transform& transform = part->rigidBody->getTransform(); const rp::Transform& transform = part->rigidBody->getTransform();

View file

@ -105,7 +105,7 @@ void renderParts() {
shader->set("viewPos", camera.cameraPos); shader->set("viewPos", camera.cameraPos);
// TODO: Same as todo in src/physics/simulation.cpp // TODO: Same as todo in src/physics/simulation.cpp
for (InstanceRef inst : workspace->GetChildren()) { for (InstanceRef inst : workspace()->GetChildren()) {
if (inst->GetClass()->className != "Part") continue; if (inst->GetClass()->className != "Part") continue;
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst); std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);