From a3d2026a3527ab632662be484f81282360889665 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 7 Feb 2025 01:11:09 +0100 Subject: [PATCH] feat: deserialization... among other things --- editor/mainwindow.cpp | 41 ++++++++++---- editor/mainwindow.h | 1 + src/common.h | 2 +- src/datatypes/base.cpp | 36 ++++++++++-- src/datatypes/base.h | 10 +++- src/datatypes/cframe.cpp | 32 +++++++++++ src/datatypes/cframe.h | 2 + src/datatypes/meta.cpp | 24 +++++++- src/datatypes/meta.h | 6 ++ src/datatypes/vector.cpp | 6 ++ src/datatypes/vector.h | 1 + src/objects/base/instance.cpp | 36 ++++++++++++ src/objects/base/instance.h | 1 + src/objects/datamodel.cpp | 103 +++++++++++++++++++++++++++++++++- src/objects/datamodel.h | 31 +++++++++- src/objects/meta.cpp | 10 ++++ src/objects/meta.h | 8 +++ src/objects/part.cpp | 5 ++ src/objects/part.h | 6 +- src/objects/workspace.h | 2 +- src/rendering/renderer.cpp | 15 +++++ 21 files changed, 350 insertions(+), 28 deletions(-) create mode 100644 src/objects/meta.cpp create mode 100644 src/objects/meta.h diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index f811be6..0c46f91 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -18,6 +18,7 @@ #include "objects/datamodel.h" #include "physics/simulation.h" #include "objects/part.h" +#include "qfiledialog.h" #include "qitemselectionmodel.h" #include "qobject.h" #include "qsysinfo.h" @@ -36,14 +37,7 @@ MainWindow::MainWindow(QWidget *parent) timer.start(33, this); setMouseTracking(true); - connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) { - if (selected.count() == 0) return; - - std::optional inst = selected.count() == 0 ? std::nullopt - : std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this()); - - ui->propertiesView->setSelected(inst); - }); + 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(); }); @@ -65,11 +59,23 @@ MainWindow::MainWindow(QWidget *parent) }); connect(ui->actionSave, &QAction::triggered, this, [&]() { - pugi::xml_document doc; - pugi::xml_node node = doc.append_child("openblocks"); - workspace()->Serialize(&node); + std::optional path; + if (!dataModel->HasFile()) + path = QFileDialog::getSaveFileName(this, QString::fromStdString("Save " + dataModel->name), "", "*.obl").toStdString(); + if (path == "") return; - doc.print(std::cout); + dataModel->SaveToFile(path); + }); + + connect(ui->actionOpen, &QAction::triggered, this, [&]() { + std::string path = QFileDialog::getOpenFileName(this, "Load file", "", "*.obl").toStdString(); + if (path == "") return; + std::shared_ptr newModel = DataModel::LoadFromFile(path); + dataModel = newModel; + delete ui->explorerView->selectionModel(); + ui->explorerView->reset(); + ui->explorerView->setModel(new ExplorerModel(dataModel)); + ConnectSelectionChangeHandler(); }); // ui->explorerView->Init(ui); @@ -104,6 +110,17 @@ MainWindow::MainWindow(QWidget *parent) syncPartPhysics(ui->mainWidget->lastPart); } +void MainWindow::ConnectSelectionChangeHandler() { + connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) { + if (selected.count() == 0) return; + + std::optional inst = selected.count() == 0 ? std::nullopt + : std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this()); + + ui->propertiesView->setSelected(inst); + }); +} + static std::chrono::time_point lastTime = std::chrono::steady_clock::now(); void MainWindow::timerEvent(QTimerEvent* evt) { if (evt->timerId() != timer.timerId()) { diff --git a/editor/mainwindow.h b/editor/mainwindow.h index 2779d5b..4879fe0 100644 --- a/editor/mainwindow.h +++ b/editor/mainwindow.h @@ -28,5 +28,6 @@ private: void updateSelectedTool(); void timerEvent(QTimerEvent*) override; + void ConnectSelectionChangeHandler(); }; #endif // MAINWINDOW_H diff --git a/src/common.h b/src/common.h index 74fc8f9..2c341b0 100644 --- a/src/common.h +++ b/src/common.h @@ -15,7 +15,7 @@ typedef std::function oldSelection, std::vecto extern Camera camera; extern std::shared_ptr dataModel; -inline std::shared_ptr workspace() { return dataModel->workspace; } +inline std::shared_ptr workspace() { return std::dynamic_pointer_cast(dataModel->services["Workspace"]); } extern std::optional hierarchyPreUpdateHandler; extern std::optional hierarchyPostUpdateHandler; diff --git a/src/datatypes/base.cpp b/src/datatypes/base.cpp index 3594fef..97c036a 100644 --- a/src/datatypes/base.cpp +++ b/src/datatypes/base.cpp @@ -1,9 +1,10 @@ #include "base.h" +#include "meta.h" #define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \ Data::CLASS_NAME::~CLASS_NAME() = default; \ Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \ -const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, }; \ +const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, .deserializer = &Data::CLASS_NAME::Deserialize }; \ const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; }; \ void Data::CLASS_NAME::Serialize(pugi::xml_node* node) const { node->text().set(std::string(this->ToString())); } @@ -13,14 +14,10 @@ Data::Null::Null() {}; Data::Null::~Null() = default; const Data::TypeInfo Data::Null::TYPE = { .name = "null", + .deserializer = &Data::Null::Deserialize, }; const Data::TypeInfo& Data::Null::GetType() const { return Data::Null::TYPE; }; -IMPL_WRAPPER_CLASS(Bool, bool, "bool") -IMPL_WRAPPER_CLASS(Int, int, "int") -IMPL_WRAPPER_CLASS(Float, float, "float") -IMPL_WRAPPER_CLASS(String, std::string, "string") - const Data::String Data::Null::ToString() const { return Data::String("null"); } @@ -29,18 +26,45 @@ void Data::Null::Serialize(pugi::xml_node* node) const { node->text().set("null"); } +Data::Variant Data::Null::Deserialize(pugi::xml_node* node) { + return Data::Null(); +} + +// + +IMPL_WRAPPER_CLASS(Bool, bool, "bool") +IMPL_WRAPPER_CLASS(Int, int, "int") +IMPL_WRAPPER_CLASS(Float, float, "float") +IMPL_WRAPPER_CLASS(String, std::string, "string") + const Data::String Data::Bool::ToString() const { return Data::String(value ? "true" : "false"); } +Data::Variant Data::Bool::Deserialize(pugi::xml_node* node) { + return Data::Bool(node->text().as_bool()); +} + const Data::String Data::Int::ToString() const { return Data::String(std::to_string(value)); } +Data::Variant Data::Int::Deserialize(pugi::xml_node* node) { + return Data::Int(node->text().as_int()); +} + const Data::String Data::Float::ToString() const { return Data::String(std::to_string(value)); } +Data::Variant Data::Float::Deserialize(pugi::xml_node* node) { + return Data::Float(node->text().as_float()); +} + const Data::String Data::String::ToString() const { return *this; +} + +Data::Variant Data::String::Deserialize(pugi::xml_node* node) { + return Data::String(node->text().as_string()); } \ No newline at end of file diff --git a/src/datatypes/base.h b/src/datatypes/base.h index 781417f..1d44657 100644 --- a/src/datatypes/base.h +++ b/src/datatypes/base.h @@ -1,8 +1,8 @@ #pragma once -#include #include - +#include +#include #define DEF_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE) class CLASS_NAME : public Data::Base { \ const WRAPPED_TYPE value; \ @@ -15,11 +15,16 @@ public: \ \ virtual const Data::String ToString() const override; \ virtual void Serialize(pugi::xml_node* node) const override; \ + static Data::Variant Deserialize(pugi::xml_node* node); \ }; namespace Data { + class Variant; + typedef std::function Deserializer; + struct TypeInfo { std::string name; + Deserializer deserializer; TypeInfo(const TypeInfo&) = delete; }; @@ -41,6 +46,7 @@ namespace Data { virtual const Data::String ToString() const override; virtual void Serialize(pugi::xml_node* node) const override; + static Data::Variant Deserialize(pugi::xml_node* node); }; DEF_WRAPPER_CLASS(Bool, bool) diff --git a/src/datatypes/cframe.cpp b/src/datatypes/cframe.cpp index 40b28f9..9ea6199 100644 --- a/src/datatypes/cframe.cpp +++ b/src/datatypes/cframe.cpp @@ -5,6 +5,19 @@ #include #define GLM_ENABLE_EXPERIMENTAL #include +// #include "meta.h" // IWYU pragma: keep + +Data::CFrame::CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22) + : translation(x, y, z) + , rotation({ + // { R00, R01, R02 }, + // { R10, R11, R12 }, + // { R20, R21, R22 }, + { R00, R10, R20 }, + { R01, R11, R21 }, + { R02, R12, R22 }, + }) { +} Data::CFrame::CFrame(glm::vec3 translation, glm::mat3 rotation) : translation(translation) @@ -41,6 +54,7 @@ Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 Data::CFrame::~CFrame() = default; const Data::TypeInfo Data::CFrame::TYPE = { .name = "CoordinateFrame", + .deserializer = &Data::CFrame::Deserialize, }; const Data::TypeInfo& Data::CFrame::GetType() const { return Data::Vector3::TYPE; }; @@ -97,3 +111,21 @@ void Data::CFrame::Serialize(pugi::xml_node* node) const { node->append_child("R21").text().set(std::to_string(this->rotation[1][2])); node->append_child("R22").text().set(std::to_string(this->rotation[2][2])); } + + +Data::Variant Data::CFrame::Deserialize(pugi::xml_node* node) { + return Data::CFrame( + node->child("X").text().as_float(), + node->child("Y").text().as_float(), + node->child("Z").text().as_float(), + node->child("R00").text().as_float(), + node->child("R01").text().as_float(), + node->child("R02").text().as_float(), + node->child("R10").text().as_float(), + node->child("R11").text().as_float(), + node->child("R12").text().as_float(), + node->child("R20").text().as_float(), + node->child("R21").text().as_float(), + node->child("R22").text().as_float() + ); +} \ No newline at end of file diff --git a/src/datatypes/cframe.h b/src/datatypes/cframe.h index 766e7cb..fbbe37e 100644 --- a/src/datatypes/cframe.h +++ b/src/datatypes/cframe.h @@ -22,6 +22,7 @@ namespace Data { // CFrame(float x, float y, float z); // CFrame(const glm::vec3&); // CFrame(const rp::Vector3&); + CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22); CFrame(const rp::Transform&); CFrame(Data::Vector3 position, glm::quat quat); CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up = Data::Vector3(0, 1, 0)); @@ -32,6 +33,7 @@ namespace Data { virtual const Data::String ToString() const override; virtual void Serialize(pugi::xml_node* parent) const override; + static Data::Variant Deserialize(pugi::xml_node* node); operator glm::mat4() const; operator rp::Transform() const; diff --git a/src/datatypes/meta.cpp b/src/datatypes/meta.cpp index 839750b..5d6a513 100644 --- a/src/datatypes/meta.cpp +++ b/src/datatypes/meta.cpp @@ -1,4 +1,6 @@ #include "meta.h" +#include "datatypes/base.h" +#include "datatypes/cframe.h" #include Data::String Data::Variant::ToString() const { @@ -11,4 +13,24 @@ void Data::Variant::Serialize(pugi::xml_node* node) const { std::visit([&](auto&& it) { it.Serialize(node); }, this->wrapped); -} \ No newline at end of file +} + +Data::Variant Data::Variant::Deserialize(pugi::xml_node* node) { + if (Data::TYPE_MAP.count(node->name()) == 0) { + fprintf(stderr, "Unknown type for instance: '%s'\n", node->name()); + abort(); + } + + const Data::TypeInfo* type = Data::TYPE_MAP[node->name()]; + return type->deserializer(node); +} + +std::map Data::TYPE_MAP = { + { "null", &Data::Null::TYPE }, + { "bool", &Data::Bool::TYPE }, + { "int", &Data::Int::TYPE }, + { "float", &Data::Float::TYPE }, + { "string", &Data::String::TYPE }, + { "Vector3", &Data::Vector3::TYPE }, + { "CoordinateFrame", &Data::CFrame::TYPE }, +}; \ No newline at end of file diff --git a/src/datatypes/meta.h b/src/datatypes/meta.h index 3c14bba..6df3804 100644 --- a/src/datatypes/meta.h +++ b/src/datatypes/meta.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "base.h" #include "vector.h" #include "cframe.h" @@ -30,6 +31,11 @@ namespace Data { template Variant(T obj) : wrapped(obj) {} template T get() { return std::get(wrapped); } Data::String ToString() const; + void Serialize(pugi::xml_node* node) const; + static Data::Variant Deserialize(pugi::xml_node* node); }; + + // Map of all data types to their type names + extern std::map TYPE_MAP; } \ No newline at end of file diff --git a/src/datatypes/vector.cpp b/src/datatypes/vector.cpp index 881de02..c5501e7 100644 --- a/src/datatypes/vector.cpp +++ b/src/datatypes/vector.cpp @@ -1,5 +1,6 @@ #include "vector.h" #include +#include "meta.h" // IWYU pragma: keep Data::Vector3::Vector3(const glm::vec3& src) : vector(src) {}; Data::Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, src.z)) {}; @@ -8,6 +9,7 @@ Data::Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, Data::Vector3::~Vector3() = default; const Data::TypeInfo Data::Vector3::TYPE = { .name = "Vector3", + .deserializer = &Data::Vector3::Deserialize, }; const Data::TypeInfo& Data::Vector3::GetType() const { return Data::Vector3::TYPE; }; @@ -50,3 +52,7 @@ void Data::Vector3::Serialize(pugi::xml_node* node) const { node->append_child("Y").text().set(std::to_string(this->Y())); node->append_child("Z").text().set(std::to_string(this->Z())); } + +Data::Variant Data::Vector3::Deserialize(pugi::xml_node* node) { + return Data::Vector3(node->child("X").text().as_float(), node->child("Y").text().as_float(), node->child("Z").text().as_float()); +} diff --git a/src/datatypes/vector.h b/src/datatypes/vector.h index 96d8349..178eb08 100644 --- a/src/datatypes/vector.h +++ b/src/datatypes/vector.h @@ -25,6 +25,7 @@ namespace Data { virtual const Data::String ToString() const override; virtual void Serialize(pugi::xml_node* node) const override; + static Data::Variant Deserialize(pugi::xml_node* node); operator glm::vec3() const; operator rp::Vector3() const; diff --git a/src/objects/base/instance.cpp b/src/objects/base/instance.cpp index 3a2951a..9d2dea4 100644 --- a/src/objects/base/instance.cpp +++ b/src/objects/base/instance.cpp @@ -3,6 +3,7 @@ #include "../../datatypes/meta.h" #include "datatypes/base.h" #include "objects/base/member.h" +#include "objects/meta.h" #include #include #include @@ -163,4 +164,39 @@ void Instance::Serialize(pugi::xml_node* parent) { for (InstanceRef child : this->children) { child->Serialize(&node); } +} + +InstanceRef Instance::Deserialize(pugi::xml_node* node) { + std::string className = node->attribute("class").value(); + if (INSTANCE_MAP.count(className) == 0) { + fprintf(stderr, "Unknown type for instance: '%s'\n", className.c_str()); + abort(); + } + // This will error if an abstract instance is used in the file. Oh well, not my prob rn. + // printf("What are you? A %s sandwich\n", className.c_str()); + InstanceRef object = INSTANCE_MAP[className]->constructor(); + object->GetChildren(); + + // const InstanceType* type = INSTANCE_MAP.at(className); + + // Read properties + pugi::xml_node propertiesNode = node->child("Properties"); + for (pugi::xml_node propertyNode : propertiesNode) { + std::string propertyName = propertyNode.attribute("name").value(); + auto meta_ = object->GetPropertyMeta(propertyName); + if (!meta_.has_value()) { + fprintf(stderr, "Attempt to set unknown property '%s' of %s\n", propertyName.c_str(), object->GetClass()->className.c_str()); + continue; + } + Data::Variant value = Data::Variant::Deserialize(&propertyNode); + object->SetPropertyValue(propertyName, value); + } + + // Read children + for (pugi::xml_node childNode : node->children("Item")) { + InstanceRef child = Instance::Deserialize(&childNode); + object->AddChild(child); + } + + return object; } \ No newline at end of file diff --git a/src/objects/base/instance.h b/src/objects/base/instance.h index 46fd6c6..c696877 100644 --- a/src/objects/base/instance.h +++ b/src/objects/base/instance.h @@ -72,6 +72,7 @@ public: // Serialization void Serialize(pugi::xml_node* parent); + static std::shared_ptr Deserialize(pugi::xml_node* node); }; typedef std::shared_ptr InstanceRef; diff --git a/src/objects/datamodel.cpp b/src/objects/datamodel.cpp index 7dca703..f450de1 100644 --- a/src/objects/datamodel.cpp +++ b/src/objects/datamodel.cpp @@ -1,6 +1,18 @@ #include "datamodel.h" +#include "base/service.h" +#include "objects/base/instance.h" +#include "objects/base/service.h" #include "workspace.h" +#include +#include #include +#include + +// TODO: Move this to a different file +// ONLY add services here, all types are expected to inherit from Service, or errors WILL occur +std::map(std::weak_ptr)>> SERVICE_CONSTRUCTORS = { + { "Workspace", &Workspace::Create }, +}; const InstanceType DataModel::TYPE = { .super = &Instance::TYPE, @@ -14,9 +26,96 @@ const InstanceType* DataModel::GetClass() { DataModel::DataModel() : Instance(&TYPE) { + this->name = "Place"; } void DataModel::Init() { - this->workspace = std::make_shared(shared()); - this->workspace->InitService(); + // Create the workspace if it doesn't exist + if (this->services.count("Workspace") == 0) + this->services["Workspace"] = std::make_shared(shared()); + + // Init all services + for (auto [_, service] : this->services) { + service->InitService(); + } +} + +void DataModel::SaveToFile(std::optional path) { + if (!path.has_value() && !this->currentFile.has_value()) { + fprintf(stderr, "Cannot save DataModel because no path was provided.\n"); + abort(); + } + + std::string target = path.has_value() ? path.value() : this->currentFile.value(); + + std::ofstream outStream(target); + + pugi::xml_document doc; + pugi::xml_node root = doc.append_child("openblocks"); + + for (InstanceRef child : this->GetChildren()) { + child->Serialize(&root); + } + + doc.save(outStream); + currentFile = target; + name = target; + printf("Place saved succesfully\n"); +} + +void DataModel::DeserializeService(pugi::xml_node* node) { + std::string className = node->attribute("class").value(); + if (SERVICE_CONSTRUCTORS.count(className) == 0) { + fprintf(stderr, "Unknown service: '%s'\n", className.c_str()); + abort(); + } + + printf("Adding a workspace. %d:%d:%d\n", services.count(className), services.size(), GetChildren().size()); + if (services.count(className) != 0) { + fprintf(stderr, "Service %s defined multiple times in file\n", className.c_str()); + return; + } + + // This will error if an abstract instance is used in the file. Oh well, not my prob rn. + InstanceRef object = SERVICE_CONSTRUCTORS[className](shared()); + + // Read properties + pugi::xml_node propertiesNode = node->child("Properties"); + for (pugi::xml_node propertyNode : propertiesNode) { + std::string propertyName = propertyNode.attribute("name").value(); + auto meta_ = object->GetPropertyMeta(propertyName); + if (!meta_.has_value()) { + fprintf(stderr, "Attempt to set unknown property '%s' of %s\n", propertyName.c_str(), object->GetClass()->className.c_str()); + continue; + } + Data::Variant value = Data::Variant::Deserialize(&propertyNode); + object->SetPropertyValue(propertyName, value); + } + + // Add children + for (pugi::xml_node childNode : node->children("Item")) { + InstanceRef child = Instance::Deserialize(&childNode); + object->AddChild(child); + } + + // We add the service to the list + // All services get init'd at once in InitServices + this->services[className] = std::dynamic_pointer_cast(object); +} + +std::shared_ptr DataModel::LoadFromFile(std::string path) { + std::ifstream inStream(path); + pugi::xml_document doc; + doc.load(inStream); + + pugi::xml_node rootNode = doc.child("openblocks"); + std::shared_ptr newModel = std::make_shared(); + + for (pugi::xml_node childNode : rootNode.children("Item")) { + newModel->DeserializeService(&childNode); + } + + newModel->Init(); + + return newModel; } \ No newline at end of file diff --git a/src/objects/datamodel.h b/src/objects/datamodel.h index 02a3408..28e41b8 100644 --- a/src/objects/datamodel.h +++ b/src/objects/datamodel.h @@ -5,17 +5,44 @@ class Workspace; +class DataModel; +class Service; +extern std::map(std::weak_ptr)>> SERVICE_CONSTRUCTORS; + // The root instance to all objects in the hierarchy class DataModel : public Instance { -//private: +private: + void DeserializeService(pugi::xml_node* node); public: const static InstanceType TYPE; - std::shared_ptr workspace; + std::map> services; + + std::optional currentFile; DataModel(); void Init(); static inline std::shared_ptr New() { return std::make_shared(); }; virtual const InstanceType* GetClass() override; + + template + std::shared_ptr GetService(std::string name) { + if (services.count(name) != 0) + return services[name]; + // TODO: Validate name + services[name] = SERVICE_CONSTRUCTORS[name](shared()); + } + + template + std::optional> FindService() { + if (services.count(name) != 0) + return services[name]; + return std::nullopt; + } + + // Saving/loading + inline bool HasFile() { return this->currentFile.has_value(); } + void SaveToFile(std::optional path = std::nullopt); + static std::shared_ptr LoadFromFile(std::string path); }; \ No newline at end of file diff --git a/src/objects/meta.cpp b/src/objects/meta.cpp new file mode 100644 index 0000000..878e9b8 --- /dev/null +++ b/src/objects/meta.cpp @@ -0,0 +1,10 @@ +#include "meta.h" +#include "objects/part.h" +#include "objects/workspace.h" + +std::map INSTANCE_MAP = { + { "Instance", &Instance::TYPE }, + { "Part", &Part::TYPE }, + { "Workspace", &Workspace::TYPE }, + { "DataModel", &DataModel::TYPE }, +}; \ No newline at end of file diff --git a/src/objects/meta.h b/src/objects/meta.h new file mode 100644 index 0000000..dbde8c5 --- /dev/null +++ b/src/objects/meta.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include "objects/base/instance.h" + +// Map of all instance types to their class names +extern std::map INSTANCE_MAP; \ No newline at end of file diff --git a/src/objects/part.cpp b/src/objects/part.cpp index aa36d62..cb92edd 100644 --- a/src/objects/part.cpp +++ b/src/objects/part.cpp @@ -85,6 +85,11 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par .type = &Data::CFrame::TYPE, .codec = fieldCodecOf(), .updateCallback = memberFunctionOf(&Part::onUpdated, this), + } }, { "scale", { + .backingField = &scale, + .type = &Data::Vector3::TYPE, + .codec = fieldCodecOf(), + .updateCallback = memberFunctionOf(&Part::onUpdated, this) } } } }); diff --git a/src/objects/part.h b/src/objects/part.h index f74476e..d868341 100644 --- a/src/objects/part.h +++ b/src/objects/part.h @@ -31,7 +31,11 @@ public: // TODO: Switch these over to our dedicated datatypes Data::CFrame cframe; glm::vec3 scale; - Material material; + Material material { + .diffuse = glm::vec3(0.639216f, 0.635294f, 0.647059f), + .specular = glm::vec3(0.5f, 0.5f, 0.5f), + .shininess = 32.0f, + }; bool selected = false; bool anchored = false; diff --git a/src/objects/workspace.h b/src/objects/workspace.h index afd41c9..5870ecc 100644 --- a/src/objects/workspace.h +++ b/src/objects/workspace.h @@ -12,6 +12,6 @@ public: Workspace(std::weak_ptr dataModel); // static inline std::shared_ptr New() { return std::make_shared(); }; - // static inline InstanceRef Create() { return std::make_shared(); }; + static inline std::shared_ptr Create(std::weak_ptr parent) { return std::make_shared(parent); }; virtual const InstanceType* GetClass() override; }; \ No newline at end of file diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 4312b9f..b1513e5 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -110,6 +110,21 @@ void renderParts() { if (inst->GetClass()->className != "Part") continue; std::shared_ptr part = std::dynamic_pointer_cast(inst); + // if (inst->name == "Target") printf("(%f,%f,%f):(%f,%f,%f;%f,%f,%f;%f,%f,%f)\n", + // part->cframe.X(), + // part->cframe.Y(), + // part->cframe.Z(), + // part->cframe.RightVector().X(), + // part->cframe.UpVector().X(), + // part->cframe.LookVector().X(), + // part->cframe.RightVector().Y(), + // part->cframe.UpVector().Y(), + // part->cframe.LookVector().Y(), + // part->cframe.RightVector().Z(), + // part->cframe.UpVector().Z(), + // part->cframe.LookVector().Z() + // ); + glm::mat4 model = part->cframe; model = glm::scale(model, part->scale); shader->set("model", model);